I'm following this tutorial to learn about creating shapes and colors on a canvas. Here is the issue I'm running into: When I try to run the command in the run_command method and I take the first letter of my command (command[0]), it is returning the number 98 to me. I am trying to match the first letter of the command to a letter of the alphabet, but am unable to do so. What's strange though, is that when I remove the first letter with "command.delete "b"", the letter is removed and I'm free to use the rest of the string as I please.
Here is my code:
require 'ruby-processing'
class ProcessArtist < Processing::App
def setup
background(0, 0, 0)
end
def draw
# Do Stuff
end
def key_pressed
if #queue.nil?
#queue = ""
end
if key != "\n"
#queue = #queue + key
else
warn "Time to run the command: #{#queue}"
run_command(#queue)
#queue = ""
end
end
def run_command(command)
puts "Running command: #{command}"
puts command[0]
if command[0] == "b"
command.delete "b"
command.split(",")
background(command[0].to_i,command[1].to_i,command[2].to_i)
else
puts command[0]
command.delete "b"
command.split(",")
background(command[0].to_i,command[1].to_i,command[2].to_i)
end
end
end
ProcessArtist.new(:width => 800, :height => 800,
:title => "ProcessArtist", :full_screen => false)
Ah, I see what I did wrong. It should have been:
def run_command(command)
puts "Running command: #{command}"
puts command[0]
if command[0] = "b"
command.delete "b"
command.split(",")
background(command[0].to_i,command[1].to_i,command[2].to_i)
else
puts command[0]
command.delete "b"
command.split(",")
background(command[0].to_i,command[1].to_i,command[2].to_i)
end
end
It seems like you're using ruby version older than 1.9.
In old version of ruby (1.8-), String#\[\] return Fixnum object representing ASCII value, not String object.
>> RUBY_VERSION
=> "1.8.7"
>> 'bcd'[0]
=> 98
To get string back, use one of followings:
>> 'bcd'[0,1]
=> "b"
>> 'bcd'[0..0]
=> "b"
>> 'bcd'[0].chr # this will not work in Ruby 1.9+, so not recommended.
=> "b"
For comparison:
>> 'bcd'[0] == 'b'
=> false
>> 'bcd'[0] == ?b
=> true
>> 'bcd'.start_with? 'b'
=> true
Related
I have a file that looks like this:
[noahc:~/projects/wordsquares] master(+87/-50)* ± cat wordlist/test_word_list.txt
card
apple
joe
bird
card
dart
area
rear
birdbird
after
boat
swim
north
abbe
byes
beep
If I open up an irb session, I can do:
2.0.0p247 :001 > file = File.open('./wordlist/test_word_list.txt', 'r')
=> #<File:./wordlist/test_word_list.txt>
2.0.0p247 :002 > file.readlines
=> ["card\n", "apple\n", "joe\n", "bird\n", "card\n", "dart\n", "area\n", "rear\n", "birdbird\n", "after\n", "boat\n", "swim\n", "north\n", "abbe\n", "byes\n", "beep \n", "\n"]
But, now I have a class called WordSquareGenerator:
class WordSquareGenerator
require 'pry'
require 'pry-nav'
require './lib/word_list_builder.rb'
def initialize(n, file_location)
#size_of_square = n
#file = load_file(file_location)
#word_stem_hash = WordListBuilder.new(n, #file).word_stem_hash
#word_list = nil
end
def word_square_word_list
binding.pry
#file.each do |w|
binding.pry
#word_list ? break : solve_for_word_list([word])
end
binding.pry
end
def is_list_valid?(list)
(0..#size_of_square - 1).each do |n|
(0..#size_of_square - 2).each do |m|
return false if list[n][m] != list [m][n]
end
end
#generated_list = list unless #generated_list
end
def solve_for_word_list(word_array)
if word_array.length == 4
#word_list = word_array
elsif #word_list
else
next_words = #word_stem_hash[word_array.map{|w| w[word_array.length]}.join]
next_words.each do |word|
solve_for_word_list(word_array + [word])
end
end
end
private
def load_file(file_location)
File.open(file_location, 'r')
end
end
When I run the word_square_word_list method and hit the first binding.pry, I can do:
2.0.0 (#<WordSquareGenerator:0x007ff3f91c16b0>):0 > #file.readlines
=> []
and I get an empty array for readlines. How can it be that I'm getting two different results doing the same thing, except one is inside that class and the other isn't?
At WordListBuilder you are probably reading the file already and when the action gets back to WordSquareGenerator the file is already at it's end and there's nothing else to read. First, don't do what you're doing now, that is opening the file since this leaks the file handle (you're not closing it anywhere) and someone else reading the handle is causing your code to fail.
Here's how you could do it:
class WordSquareGenerator
require 'pry'
require 'pry-nav'
require './lib/word_list_builder.rb'
def initialize(n, file_location)
#size_of_square = n
#file_location = file_location
#word_stem_hash = WordListBuilder.new(n, file_location).word_stem_hash
#word_list = nil
end
def word_square_word_list
binding.pry
IO.foreach(#file_location) do |word|
binding.pry
#word_list ? break : solve_for_word_list([word])
end
binding.pry
end
def is_list_valid?(list)
(0..#size_of_square - 1).each do |n|
(0..#size_of_square - 2).each do |m|
return false if list[n][m] != list [m][n]
end
end
#generated_list = list unless #generated_list
end
def solve_for_word_list(word_array)
if word_array.length == 4
#word_list = word_array
elsif #word_list
else
next_words = #word_stem_hash[word_array.map{|w| w[word_array.length]}.join]
next_words.each do |word|
solve_for_word_list(word_array + [word])
end
end
end
end
And you would also need to update WordListBuilder to do the same. This also has the advantage of closing the file handle automatically for you so you don't have to care about closing it yourself.
Try running this before you read the lines:
#file.seek 0
You have probably already read the lines, and you have to seek back to the start of the file before you read them again.
Sample IRB session:
irb(main):001:0> f = File.new 'test.txt' # already existing file
=> #<File:test.txt>
irb(main):002:0> f.readlines
=> ["this", "is", "a", "test"]
irb(main):003:0> f.readlines
=> []
irb(main):004:0> f.seek 0
=> 0
irb(main):005:0> f.readlines
=> ["this", "is", "a", "test"]
You could even make it a method:
def readlines
#file.seek 0
#file.readlines
end
Also, make sure to close your file (#file.close)! You should only leave it open for as little time as possible. And you definitely should not leave it open for the whole program. If you don't want to worry about that, just store the lines in a variable instead of keeping the file:
#lines = File.open(file_location) {|f|
f.readlines
}
# you could also use the shortcut form
# #lines = File.open(file_location, &:readlines)
So, I'm trying to parse a Cucumber file (*.feature), in order to identify how many lines each Scenario has.
Example of file:
Scenario: Add two numbers
Given I have entered 50 into the calculator
And I have entered 70 into the calculator
When I press add
Then the result should be 120 on the screen
Scenario: Add many numbers
Given I have entered 50 into the calculator
And I have entered 20 into the calculator
And I have entered 20 into the calculator
And I have entered 30 into the calculator
When I press add
Then the result should be 120 on the screen
So, I'm expecting to parse this file and get results like:
Scenario: Add two numbers ---> it has 4 lines!
Scenario: Add many numbers ---> it has 6 lines!
What's the best approach to do that?
Enumerable#slice_before is pretty much tailor-made for this.
File.open('your cuke scenario') do |f|
f.slice_before(/^\s*Scenario:/) do |scenario|
title = scenario.shift.chomp
ct = scenario.map(&:strip).reject(&:empty?).size
puts "#{title} --> has #{ct} lines"
end
end
Why don't you start simple? Like #FeRtoll suggested, going line by line might be the easiest solution. Something as simple as the following might be what you are looking for :
scenario = nil
scenarios = Hash.new{ |h,k| h[k] = 0 }
File.open("file_or_argv[0]_or_whatever.features").each do |line|
next if line.strip.empty?
if line[/^Scenario/]
scenario = line
else
scenarios[scenario] += 1
end
end
p scenarios
Output :
{"Scenario: Add two numbers \n"=>4, "Scenario: Add many numbers\n"=>6}
This is the current piece of code I'm working on (based on Kyle Burton approach):
def get_scenarios_info
#scenarios_info = [:scenario_name => "", :quantity_of_steps => []]
#all_files.each do |file|
line_counter = 0
File.open(file).each_line do |line|
line.chomp!
next if line.empty?
line_counter = line_counter + 1
if line.include? "Scenario:"
#scenarios_info << {:scenario_name => line, :scenario_line => line_counter, :feature_file => file, :quantity_of_steps => []}
next
end
#scenarios_info.last[:quantity_of_steps] << line
end
end
#TODO: fix me here!
#scenarios_info.each do |scenario|
if scenario[:scenario_name] == ""
#scenarios_info.delete(scenario)
end
scenario[:quantity_of_steps] = scenario[:quantity_of_steps].size
end
puts #scenarios_info
end
FeRtoll suggested a good approach: accumulating by section. The simplest way to parse it for me was to scrub out parts that I can ignore (i.e. comments) and then split into sections:
file = ARGV[0] or raise "Please supply a file name to parse"
def preprocess file
data = File.read(file)
data.gsub! /#.+$/, '' # strip (ignore) comments
data.gsub! /#.+$/, '' # strip (ignore) tags
data.gsub! /[ \t]+$/, '' # trim trailing whitespace
data.gsub! /^[ \t]+/, '' # trim leading whitespace
data.split /\n\n+/ # multiple blanks separate sections
end
sections = {
:scenarios => [],
:background => nil,
:feature => nil,
:examples => nil
}
parts = preprocess file
parts.each do |part|
first_line, *lines = part.split /\n/
if first_line.include? "Scenario:"
sections[:scenarios] << {
:name => first_line.strip,
:lines => lines
}
end
if first_line.include? "Feature:"
sections[:feature] = {
:name => first_line.strip,
:lines => lines
}
end
if first_line.include? "Background:"
sections[:background] = {
:name => first_line.strip,
:lines => lines
}
end
if first_line.include? "Examples:"
sections[:examples] = {
:name => first_line.strip,
:lines => lines
}
end
end
if sections[:feature]
puts "Feature has #{sections[:feature][:lines].size} lines."
end
if sections[:background]
puts "Background has #{sections[:background][:lines].size} steps."
end
puts "There are #{sections[:scenarios].size} scenarios:"
sections[:scenarios].each do |scenario|
puts " #{scenario[:name]} has #{scenario[:lines].size} steps"
end
if sections[:examples]
puts "Examples has #{sections[:examples][:lines].size} lines."
end
HTH
I have a ruby hash which looks like
{"10.1.1.6"=>"nick", "127.0.0.1"=>"nick1"}
But I can't manage to check if a certain string is already in the Hash. I tried has_value?, getting array of values using values then using include? to check if it contains it, but always returns false, when I know that it exists. For example, I try to add "172.16.10.252"=>"nick" to the hash and I do:
class SomeClass
def initialize(*args)
super(*args)
#nicks = Hash.new
end
def serve(io)
loop do
line = io.readline
ip = io.peeraddr[3]
begin
if /NICK (.*)/ =~ line
nick = $1
if #nicks.has_value?(nick) # it fails here
puts "New nick #{$1}"
#nicks[ip] = nick.gsub("\r", "")
io.puts "Your new nick is #{nick}"
else
message = {:ERROR => "100", :INFO=>"#{nick}"}.to_json
io.puts message
end
end
rescue Exception => e
puts "Exception! #{e}-#{e.backtrace}"
end
end
end
end
On irb it works fine, but on my script it doesn't
1.9.3p125 :001 > h = {"10.1.1.6"=>"nick", "127.0.0.1"=>"nick1"}
=> {"10.1.1.6"=>"nick", "127.0.0.1"=>"nick1"}
1.9.3p125 :002 > h.has_value?('nick')
=> true
1.9.3p125 :003 > if h.has_value?('nick')
1.9.3p125 :004?> puts "yes"
1.9.3p125 :005?> else
1.9.3p125 :006 > puts "no"
1.9.3p125 :007?> end
yes
=> nil
1.9.3p125 :008 >
What I'm doing wrong?
I'm not sure if you're using "$1" the way you intend to.
In your code at this line:
if /NICK (.*)/ =~ line
nick = $1
if #nicks.has_value?(nick) # it fails here
puts "New nick #{$1}"
if line is "NICK says a bunch of things", $1 will be "says a bunch of things". So you're not really looking for the value 'nick' in your hash, but for 'says a bunch of things'.
You should check how your regex is working, I wouldn't say anything is wrong with a hash.
I have a short script that uses regular expressions to search a file for a specific phrase that a user types in. Basically, it's a simple search box.
I'm now trying to make this search box have a GUI, so that users are able to type into a box, and have their matches 'alerted' to them.
I'm new to using ruby shoes in any great detail, and have been using the examples on TheShoeBox website.
Can anyone point out where I'm going wrong with my code?
Here is my command line version that works:
string = File.read('db.txt')
puts "Enter what you're looking for below"
begin
while(true)
break if string.empty?
print "Search> "; STDOUT.flush; phrase = gets.chop
break if phrase.empty?
names = string.split(/\n/)
matches = names.select { |name| name[/#{phrase}/i] }
puts "\n \n"
puts matches
puts "\n \n"
end
end
Here is my attempt at using it within Ruby Shoes:
Shoes.app :title => "Search v0.1", :width => 300, :height => 150 do
string = File.read('db.txt')
names = string.split(/\n/)
matches = names.select { |name| name[/#{phrase}/i] }
def search(text)
text.tr! "A-Za-z", "N-ZA-Mn-za-m"
end
#usage = <<USAGE
Search - This will search for the inputted text within the database
USAGE
stack :margin => 10 do
para #usage
#input = edit_box :width => 200
end
flow :margin => 10 do
button('Search') { #output.matches }
end
stack(:margin => 0) { #output = para }
end
Many thanks
Well, for starters, the first code bit can be neatened up.
file = File.open 'db.txt', 'rb'
puts "Enter (regex) search term or quit:"
exit 1 unless file.size > 0
loop do
puts
print "query> "
redo if ( query = gets.chomp ).empty?
exit 0 if query == "quit"
file.each_line do |line|
puts "#{file.lineno}: #{line}" if line =~ /#{query}/i
end
file.rewind
end
The rb option lets it work as expected in Windows (especially with Shoes, you should try and be platform-independent). chomp strips off \r\n and \n but not a for example, while chop just blindly takes off the last character. loop do end is nicer than while true. Also why store matches in a variable? Just read through the file line by line (which allows for CRLF endings) as opposed to splitting by \n although the residual \r wouldn't really pose much of a problem...
As for the Shoes bit:
Shoes.app :title => "Search v0.2", :width => 500, :height => 600 do
#file = File.open 'db.txt', 'rb'
def search( file, query )
file.rewind
file.select {|line| line =~ /#{query}/i }.map {|match| match.chomp }
end
stack :margin => 10 do
#input = edit_line :width => 400
button "search" do
matches = search( #file, #input.text )
#output.clear
#output.append do
matches.empty? ?
title( "Nothing found :(" ) :
title( "Results\n" )
end
matches.each do |match|
#output.append { para match }
end
end
#output = stack { title "Search for something." }
end
end
You never defined #output.matches or called your search() method. See if it makes sense now.
Using Ruby 1.9.2
Problem
Compare the content, not the results, of two procs. I understand the results can't be tested because of the halting problem but that's OK; I don't want to test the results anyway.
For instance
proc {#x == "x"} == proc {#x == "x"} => false # doh!
That returns false because the objects inside the procs are not the same.
My clunky solution
I have a work around solution that kinda sorta does what I want but it doesn't really test that the proc is "equal" to what I put in it. In my specific case the format of my procs will always be boolean tests on instance variables like this:
{#x == "x" && #y != "y" || #z == String}
I wrote a method that builds classes dynamically and creates instance variables set to specified values:
def create_proc_tester(property_value_hash)
new_class = Class.new.new
new_class.class.class_eval do
define_method(:xql?) { |&block| instance_eval &block }
end
property_value_hash.each do |key, value|
new_class.instance_variable_set("##{key}", value)
end
new_class
end
Which could be used something like this:
class Foo
attr_accessor :block
end
foo = Foo.new
foo.block = proc {#x == "x" && #y != "y" || #z == String}
tester = create_proc_tester(:x => "x", :y => "y", :z => Fixnum)
puts "Test #1: #{tester.xql? &foo.block}"
tester = create_proc_tester(:x => "x", :y => "x", :z => String)
puts "Test #2: #{tester.xql? &foo.block}"
> Test #1: false
> Test #2: true
.
.
That's all great and wonderful but I want to know if there is a better, more meta, way to do this that actually tests the contents of the proc not just a work around that solves my specific problem; something that could be used to test any proc.
I was thinking there might be a way to use the Ruby parser to get something to compare but I have no idea how. I'm researching it now but thought I'd try to see if anyone here has done this before and knows how. That might be a dead-end though because of the dynamic nature of Ruby but that's where I'm looking now.
If you're using Ruby 1.9, you may be able to use the sourcify gem.
$ irb
> require 'sourcify'
=> true
> a = proc {#x == "x"}
=> #<Proc:0x9ba4240#(irb):2>
> b = proc {#x == %{x}}
=> #<Proc:0x9ba23f0#(irb):3>
> a == b
=> false
> a.to_source == b.to_source
=> true
> RUBY_VERSION
=> "1.9.2"
We also ran into the ParseTree/Ruby 1.9 incompatibility problem at my company.
$ sudo gem install ruby2ruby ParseTree
require 'parse_tree'
require 'ruby2ruby'
require 'parse_tree_extensions'
# All of these are the same:
proc { puts 'a' }.to_ruby # => "proc { puts(\"a\") }"
lambda { puts "a" }.to_ruby # => "proc { puts(\"a\") }"
Proc.new { puts %{a} }.to_ruby # => "proc { puts(\"a\") }"
# If you need to do this with classes:
class Bar; define_method(:foo) { 'a' }; end
puts Ruby2Ruby.new.process(Unifier.new.process(ParseTree.translate(Bar)))
# will print this:
# class Bar < Object
# def foo
# "a"
# end
# end