I tried to have user input function using code on this page: A simple Racket terminal interaction
(define entry_list (for/list ([line (in-lines)]
#:break (string=? line "done"))
(println line)))
(println entry_list)
Output is:
this
"this "
is
"is "
a
"a "
test
"test"
for testing only
"for testing only"
done
'(#<void> #<void> #<void> #<void> #<void>)
Why is the list consisting of only "void" items?
That is because the println function returns #<void>. If instead of println you put something that returned a different value for each line you would end up with a more interesting list.
For example, the following code should return a list with the lines that you typed in:
(define entry_list
(for/list ([line (in-lines)]
#:break (string=? line "done"))
line))
If you just want to print the lines then you could have used for instead of for/list, to avoid creating an useless list of voids at the end:
Related
I'm writing a test to check a function (called automatically by GenServer when a new file enters a folder) that calls other functions in the same module with pipes in order to read a file, process its content to insert it if needed and returns a list (:errors and :ok maps).
results looks like :
[
error: "Data not found",
ok: %MyModule{
field1: field1data,
field2: field2data
},
ok: %MyModule{
field1: field1data,
field2: field2data
},
error: "Data not found"
the code :
def processFile(file) do
insertResultsMap =
File.read!(file)
|> getLines()
|> extractMainData()
|> Enum.map(fn(x) -> insertLines(x) end)
|> Enum.group_by(fn x -> elem(x, 0) end)
handleErrors(Map.get(insertResultsMap, :error))
updateAnotherTableWithLines(Map.get(insertResultsMap, :ok))
end
defp getLines(docContent) do
String.split(docContent, "\n")
end
defp extractMainData(docLines) do
Enum.map(fn(x) -> String.split(x, ",") end)
end
defp insertLines([field1, field2, field3, field4]) do
Attrs = %{
field1: String.trim(field1),
field2: String.trim(field2),
field3: String.trim(field3),
field4: String.trim(field4)
}
mymodule.create_stuff(Attrs)
end
defp handleErrors(errors) do
{:ok, file} = File.open(#errorsFile, [:append])
saveErrors(file, errors)
File.close(file)
end
defp saveErrors(_, []), do: :ok
defp saveErrors(file, [{:error, changeset}|rest]) do
changes = for {key, value} <- changeset.changes do
"#{key} #{value}"
end
errors = for {key, {message, _}} <- changeset.errors do
"#{key} #{message}"
end
errorData = "data: #{Enum.join(changes, ", ")} \nErrors: #{Enum.join(errors, ", ")}\n\n"
IO.binwrite(file, errorData)
saveErrors(file, rest)
end
defp updateAnotherTableWithLines(insertedLines) do
Enum.map(insertedLines, fn {:ok, x} -> updateOtherTable(x) end)
end
defp updateOtherTable(dataForUpdate) do
"CLOSE" -> otherModule.doStuff(dataForUpdate.field1, dataForUpdate.field2)
end
I have several questions, and some will be pretty basic since I'm still learning :
What do you think of the code ? Any advices ? (take into account I voluntarily obfuscated names).
If I want to test this, is it the right way to test only processFile function ? Or should I make public more of them and test them individually ?
When I test the processFile function, I check that I'm receiving a list. Any way to make sure this list has only elements I'm waiting for, thus error: "String" or ok: %{}" ?
What do you think of the code? Any advices? (take into account I voluntarily obfuscated names).
Opinion based.
If I want to test this, is it the right way to test only processFile function?
Yes.
Or should I make public more of them and test them individually?
No, this is an implementation detail and testing it is an anti-pattern.
When I test the processFile function, I check that I'm receiving a list. Any way to make sure this list has only elements I'm waiting for, thus error: "String" or ok: %{}"?
You receive a Keyword. To check the explicit value, one might use:
foo = processFile(file)
assert not is_nil(foo[:ok])
OTOH, I’d better return a map from there and pattern match it:
assert %{ok: _} = processFile(file)
To assert that the result does not have anything save for :oks and :errors, one might use list subtraction:
assert Enum.uniq(Keyword.keys(result)) -- [:ok, :error] == []
So I'm trying to make a lottery program where you pick a animal, letter, and number, those are put into a array and compared to another that has the parts chosen by random.
Testing with what I call the animal round.
I have a while loop for invalid entries, that it will not move on till one of the four animals is accepted. But when it does that, the variable invalid goes to false and the coding after it doesn't get used at all. I had this problem last night, and when I finally gave up and went to bed, I decided I'll write it out on flowgorithm (If you haven't heard it makes a flow chart and you can go through programming with it step by step).
I made it, and it worked like expected, I copy and paste it over, and I get the exact same problem as last night.
Here is the code.
#import library
import random
#get variables
game = True
invalid = True
animalarray = [""]
animalarray.append("tiger")
animalarray.append("cow")
animalarray.append("turtle")
animalarray.append("bird")
lotteryarray = [""]
#game loop
#animal round
print("Pick a animal: ")
print("tiger")
print("cow")
print("turtle")
print("bird")
print(" ")
lotteryarray[0] = input()
#while loop for invalid entry
while invalid == True:
if lotteryarray[0] == "tiger" or lotteryarray[0] == "cow" or lotteryarray[0] == "turtle" or lotteryarray[0] == "bird":
invalid == False
else:
print("Invalid entry!")
lotteryarray[0] = input()
print(" ")
print("You chose " + lotteryarray[0])
game == False
And this is all I get in the shell:
Pick a animal:
tiger
cow
turtle
bird
tiger
the tiger there is what I put in, it isn't being printed.
And here is the flowgorithm, like I said, in flowgorithm this works.
flowgorithm of lottery game
I figured it out.
I printed what invalid was after it was meant to change to False and it didn't change, I changed the two equal signs to one and it worked and changed the value.
I am iterating a list in the DRL file. I need to call the new Agenda after completion of the loop. But the following code calls the Agenda "B to C" for all iterations
rule "Difference in offsets"
dialect "java"
lock-on-active
when
$notification : NotificationVO()
wtOffset:Integer() from $notification.getWeightOffset();
then
System.out.println("Hello loop1");
$notification.getOffsetChngesInterval().
add((wtOffset-$notification.getInitialOffset()));
update($notification);
drools.setFocus("B to C");
rule "Last activity"
dialect "java"
salience 2
no-loop true
auto-focus false
agenda-group "B to C"
when
$notification:NotificationVO
($notification.getOffsetChngesInterval()!=null)
then
System.out.println("Rule2---"+
$notification.getOffsetChngesInterval().size());
end
In the above code i want to focus the agenda-group "B to C" only after completing the iteration of $notification.getWeightOffset();.
Two comments. (1) The abundant usage of rule attributes is something to be avoided. (2) Rule "Difference in offsets" implements a procedural paradigm: map elements of one list to create another list.
That said, I'd do the calculation of the "changes intervals" on the right hand side of a rule that triggers when there are more "weight offsets" that "changes intervals". (I'm guessing that this is a good condition.)
rule "Difference in offsets"
dialect "java"
when
$ntf: NotificationVO( weightOffset.size() > offsetChngesInterval.size(),
$initOff: initialOffset )
then
for( Integer ioff: $ntf.getWeightOffset ){
$ntf.getOffsetChngesInterval().add(ioff - $initOff );
}
update( $ntf );
System.out.println( $ntf.getOffsetChngesInterval().size());
end
The game is a word search game in an advanced lingo book and the lingo code is using [cc] which is coming up as a code fault. What is wrong or is this use of [cc] obsolete? And if so, how can it be corrected?
on getPropertyDescriptionList me
list = [:]
-- the text member with the words in it
addProp list, #pWordSource,[cc]
[#comment: "Word Source",[cc]
#format: #text,[cc]
#default: VOID]
addProp list, #pEndGameFrame,[cc]
[#comment: "End Game Frame",[cc]
#format: #marker,[cc]
#default: #next]
return list
end
I guess this is code from here, right?
That seems like an older version of Lingo syntax. [cc], apparently, stands for "continuation character". It basically makes the compiler ignore the linebreak right after it, so that it sees everything from [#comment: to #default: VOID] as one long line, which is the syntactically correct way to write it.
If I remember correctly, once upon a time, the guys who made Lingo made one more crazy decision and made the continuation character look like this: ¬ Of course, this didn't print in lots of places, so some texts like your book used things like [cc] in its place.
In modern versions of Lingo, the continuation character is \, just like in C.
I programmed in early director but have gone on to other languages in the many years since. I understand this code. The function attempts to generate a dictionary of dictionaries. in quasi-JSON:
{
'pWordSource': { ... } ,
'pEndGameFrame': { ... }
}
It is creating a string hash, then storing a "pWordSource" as a new key pointing to a 3 item hash of it's own. The system then repeats the process with a new key "pEndGameFrame", providing yet another 3 item hash. So just to expand the ellipses ... from the above code example:
{
'pWordSource': { 'comment': 'Word Source', 'format': 'text', 'default': null } ,
'pEndGameFrame': { 'End Game Frame': 'Word Source', 'format': 'marker', 'default': 'next' }
}
So I hope that explains the hash characters. It's lingo's way of saying "this is not just a string, it's a special director-specific system we're calling a symbol. It can be described in more conventional programming terms as a constant. The lingo compiler will replace your #string1 with an integer, and it's always going to be the same integer associated with #string1. Because the hash keys are actually integers rather than strings, we can change the json model to look something more like this:
{
0: { 2: 'Word Source', 3: 'text', 4: null } ,
1: { 2:'End Game Frame', 3: 'marker', 4: 'next' }
}
where:
0 -> pWordSource
1 -> pEndGameFrame
2 -> comment
3 -> format
4 -> default
So to mimic the same construction behavior in 2016 lingo, we use the newer object oriented dot syntax for calling addProp on property lists.
on getPropertyDescriptionList me
list = [:]
-- the text member with the words in it
list.addProp(#pWordSource,[ \
#comment: "Word Source", \
#format: #text, \
#default: void \
])
list.addProp(#pEndGameFrame,[ \
#comment: "End Game Frame", \
#format: #marker, \
#default: #next \
])
return list
end
Likewise, the same reference shows examples of how to use square brackets to "access" properties, then initialize them by setting their first value.
on getPropertyDescriptionList me
list = [:]
-- the text member with the words in it
list[#pWordSource] = [ \
#comment: "Word Source", \
#format: #text, \
#default: void \
]
list[#pEndGameFrame] = [ \
#comment: "End Game Frame", \
#format: #marker, \
#default: #next \
]
return list
end
And if you are still confused about what the backslashes are doing, there are other ways to make the code more vertical.
on getPropertyDescriptionList me
list = [:]
-- the text member with the words in it
p = [:]
p[#comment] = "Word Source"
p[#format] = #text
p[#default] = void
list[#pWordSource] = p
p = [:] -- allocate new dict to avoid pointer bug
p[#comment] = "End Game Frame"
p[#format] = #marker
p[#default] = #next
list[#pEndGameFrame] = p
return list
end
The above screenshot shows it working in Director 12.0 on OS X Yosemite.
I'm brand new to TCL, and am trying to wrap my brain around all the usages of "", {}, and [] that it uses. Something I'm used to doing in other languages is defining my variables prior to use, at the beginning of the application. The below code works:
puts "Please enter an integer of choice to be added: "
flush stdout
gets stdin intAnswer
puts "Please enter a second integer of choice to be added: "
flush stdout
gets stdin intAnswerTwo
puts "Please enter a third integer of choice to be added: "
flush stdout
gets stdin intAnswerThree
puts "The total of the three integers is: [expr $intAnswer + $intAnswerTwo + $intAnswerThree]"
What I'm wanting to do is define the variables prior to use. As such:
set intAnswer 0
set intAnswerTwo 0
set intAnswerThree 0
set intTotal 0
This code, placed at the beginning, doesn't work with the rest of the code. What am I missing?
The code looks absolutely fine to me, though [expr {$intAnswer + $intAnswerTwo + $intAnswerThree}] would be better (as it stops potential reinterpretation of the variables' contents, which would be both a safety and performance issue).
However, if you really want to have integers from the user, you need to validate their input. This is most easily done by writing a procedure to do the job so you can reuse it (i.e., you refactor the code to get a value so you can use a more sophisticated version and get it right once):
proc getIntFromUser {message} {
# Loop forever (until we [exit] or [return $response])
while true {
puts $message
flush stdout
set response [gets stdin]
# Important to check for EOF...
if {[eof stdin]} {
exit
}
# The validator (-strict is needed for ugly historical reasons)
if {[string is integer -strict $response]} {
return $response
}
# Not an integer, so moan about it
puts "\"$response\" is not an integer!"
}
}
Now you have that procedure, the rest of your code can become:
set intAnswer [getIntFromUser "Please enter an integer of choice to be added: "]
set intAnswerTwo [getIntFromUser "Please enter a second integer of choice to be added: "]
set intAnswerThree [getIntFromUser "Please enter a third integer of choice to be added: "]
puts "The total of the three integers is: [expr {$intAnswer + $intAnswerTwo + $intAnswerThree}]"
The art of writing good Tcl code (or good code in pretty much any other language) is knowing what are the good points to refactor. A good starting point is “if you do it twice or more, do it once and share”. It's doubly good if you can give the procedure a good name and clear interface, a clear indication that you've got it right. Indeed, you could also go for:
set total [expr {
[getIntFromUser "Please enter an integer of choice to be added: "] +
[getIntFromUser "Please enter a second integer of choice to be added: "] +
[getIntFromUser "Please enter a third integer of choice to be added: "]
}]
puts "The total of the three integers is: $total"
The results observed by the user will be identical.