I am trying to learn a little about GUI testing with Ruby & Cucumber, partially following a book called "Scripted GUI Testing with Ruby" by Ian Dees. I'm new to Ruby, and I'm facing what seems like a simple problem - undefined method. I have two classes, each in different modules. The first class will handle Win32API calls, the second represents the top level of the application (boot-up, close, find window etc). They will work a little like page objects, separating UI interaction logic from test logic. I'm getting an undefined method on the Windows API class, for user32:
#Win32API class
require 'Win32API'
class WindowsAPI
def user32(name, param_types, return_value)
Win32API.new 'user32', name, param_types, return_value
end
#find_window = user32 'FindWindow', ['P', 'P'], 'L'
end
The second:
#Application class
require_relative 'WindowsAPI'
class VideoLibrarian
#main_win_title = "VidLibMainWin"
attr_accessor :main_win_handle, :win_api
def initialize
#win_api = WindowsAPI.new
end
def Start()
system 'start "" "C:/Users/VideoAnalyser.exe"'
sleep 0.2 while (#main_win_handle = win_api.find_window.call nil, #main_win_title) <= 0
end
end
vl = VideoLibrarian.new
vl.Start
The full stack trace/ error message is:
C:/Users/Ruby Scripts/vidlibtests/WindowsAPI.rb:11:in `<class:WindowsAPI>': undefined method `user32' for WindowsAPI:Class (NoMethodError)
from C:/Users/Ruby Scripts/vidlibtests/WindowsAPI.rb:5:in `<top (required)>'
from C:/Users/Ruby Scripts/vidlibtests/VideoLibrarian.rb:3:in `require_relative'
from C:/Users/Ruby Scripts/vidlibtests/VideoLibrarian.rb:3:in `<main>'
Any help greatly appreciated!
You defined user32 as an instance method while you clearly need it to be class method of WindowsAPI class:
def self.user32(name, param_types, return_value)
Win32API.new 'user32', name, param_types, return_value
end
Related
I am making a tool in ruby which can interact with databases.
I am using amalgalite as an adapter for sqlite3.
Code:
require 'amalgalite'
# this is class RQuery
class RQuery
def db_open(db_name)
#db = Amalgalite::Database.new "#{db_name}.db"
make_class
end
def exec_this(query)
#db.execute(query)
end
def make_class
tables_list = exec_this("select name from sqlite_master where type='table'")
tables_list.each do |table|
#class_created = Object.const_set(table[0].capitalize, Class.new)
#class_created.class_eval do
define_singleton_method :first do
RQuery.new.exec_this("select * from #{table[0]} order by #{table[0]}.id ASC limit 1")
end
end
end
end
def eval_this(input)
instance_eval(input)
end
def code
print '>>'
input = gets
exit if input =~ /^q$/
puts eval_this(input)
code
end
end
Now when I am running the code everything works fine until I call table_name.first
It gives output
vbhv#fsociety ~/git/R-Query/bin $ ruby main.rb
Enter the code or q for quit
>>db_open('vbhv')
users
persons
people
programmers
>>Users.first
/home/vbhv/git/R-Query/lib/r-query.rb:36:in `instance_eval': undefined method `execute' for nil:NilClass (NoMethodError)
Did you mean? exec
from /home/vbhv/git/R-Query/lib/r-query.rb:29:in `block (3 levels) in make_class'
from (eval):1:in `eval_this'
from /home/vbhv/git/R-Query/lib/r-query.rb:36:in `instance_eval'
from /home/vbhv/git/R-Query/lib/r-query.rb:36:in `eval_this'
from /home/vbhv/git/R-Query/lib/r-query.rb:43:in `code'
from /home/vbhv/git/R-Query/lib/r-query.rb:44:in `code'
from /home/vbhv/git/R-Query/lib/r-query.rb:44:in `code'
from main.rb:4:in `<main>'
Now the 'execute' function it is talking about is inside amalgalite. What am I doing wrong here?? Thanks in Advance!
The problem in this was that the new class formed dynamically doesn't know about the connection variable '#db'. Hence the code solves the problem.
#class_created.instance_variable_set(:#database, #db)
A big thanks to Jagdeep Singh.
In homebrew on OS X, there's a DownloadStrategyDetector class, I'm making a tap and need to override a couple methods on this class to add additional download strategies (they're very niche so won't be accepted into core).
I tried simply redefining (see below) the class above my Formula class in an attempt to override the default definition, however the regular version of the class is still used.
class DownloadStrategyDetector
def self.detect_from_url(url)
# ...
end
def self.detect_from_symbol(symbol)
# ...
end
end
Is there a way to force all uses of a class to a particular definition? This is the backtrace from the call that winds up using the default definition of the class.
My code is in tester.rb and that indirectly calls resource.rb which loads download_strategy.rb which overrides my definition of DownloadStrategyDetector.
backtrace:
/usr/local/Library/Homebrew/download_strategy.rb:963:in `detect_from_symbol'
/usr/local/Library/Homebrew/download_strategy.rb:916:in `detect'
/usr/local/Library/Homebrew/resource.rb:144:in `url'
/usr/local/Library/Homebrew/software_spec.rb:62:in `url'
/usr/local/Library/Homebrew/formula.rb:1666:in `url'
/Users/camdennarzt/Developer/Ruby/homebrew-core/formula/tester.rb:68:in `<class:Tester>'
/Users/camdennarzt/Developer/Ruby/homebrew-core/formula/tester.rb:63:in `load_formula'
/usr/local/Library/Homebrew/formulary.rb:25:in `module_eval'
/usr/local/Library/Homebrew/formulary.rb:25:in `load_formula'
/usr/local/Library/Homebrew/formulary.rb:42:in `load_formula_from_path'
/usr/local/Library/Homebrew/formulary.rb:91:in `load_file'
/usr/local/Library/Homebrew/formulary.rb:82:in `klass'
/usr/local/Library/Homebrew/formulary.rb:78:in `get_formula'
/usr/local/Library/Homebrew/formulary.rb:215:in `factory'
/usr/local/Library/Homebrew/extend/ARGV.rb:29:in `block in resolved_formulae'
/usr/local/Library/Homebrew/extend/ARGV.rb:27:in `map'
/usr/local/Library/Homebrew/extend/ARGV.rb:27:in `resolved_formulae'
/usr/local/Library/Homebrew/cmd/reinstall.rb:10:in `reinstall'
/usr/local/Library/brew.rb:87:in `<main>'
I tried another strategy as well, where I added a hook to my DownloadStrategyDetector class like this, and tried to swap the methods using aliases:
class DownloadStrategyDetector
def self.singleton_method_added(name)
puts name
alias_method :detect_from_url, :detect_from_url_2 if name == :detect_from_url
alias_method :detect_from_symbol, :detect_from_symbol_2 if name == :detect_from_symbol
end
def self.detect_from_url_2(url)
# ...
end
def self.detect_from_symbol_2(symbol)
# ...
end
end
but it only printed the following, as if the class was never reopened:
singleton_method_added
detect_from_url_2
detect_from_symbol_2
So, for whatever reason there is no peek method in the ruby core Queue class. I am trying to create a child class that implements the peek method. However, I don't understand why I am getting an error. Is it not possible to use instance variables in this way? Looking at the source code for Queue, there are instance variables in the constructor of the parent class. Is there a way to reference these in the subclass?
class PeekQueue < Queue
def peek
#mutex.synchronize{
while true
if #que.empty?
raise ThreadError, "queue empty" if non_block
#waiting.push Thread.current
#mutex.sleep
else
return #que[0]
end
end
}
end
end
a = PeekQueue.new
a.push(1)
a.peek
NoMethodError: undefined method 'synchronize' for nil:NilClass
Edit: The Queue class is created at compile time, which is why I couldn't find the source on the ruby source code on github. This is what the parent class looks like:
https://gist.github.com/anonymous/574e20fea3a28663bfe2
I do not see that error:
irb(main):025:0> qq = PeekQueue.new
=> #<PeekQueue:0x000006002bf498 #que=[], #num_waiting=0, #mutex=#<Mutex:0x000006002bf420>, #cond=#<ConditionVariable:0x000006002bf3f8 #waiters={}, #waiters_mutex=#<Mutex:0x000006002bf3a8>>>
irb(main):026:0> qq.peek
NameError: undefined local variable or method `non_block' for #<PeekQueue:0x000006002bf498>
from (irb):15:in `block in peek'
from (irb):12:in `synchronize'
from (irb):12:in `peek'
from (irb):26
from /usr/bin/irb:12:in `<main>'
irb(main):027:0> qq.push 1
=> #<ConditionVariable:0x000006002bf3f8 #waiters={}, #waiters_mutex=#<Mutex:0x000006002bf3a8>>
irb(main):028:0> qq.peek
=> 1
Method #non_block seems to be an issue. But access to #mutex works with your code.
I'm trying to learn Ruby, but have a previous Java background, and I thought the best way to learn Ruby is to re-implement an old side project.
The problem that I am facing is that I get the following error
ATMSystem.rb:4:in `show_start_menu': uninitialized constant ATMSystem::BankComputer (NameError)
I am using two classes, the first is the BankComputer class, and the second is ATMSystem.
class BankComputer
attr_accessor :bank_id, :customer_accounts
##card_number = 1000
def initialize(bank_id)
#bank_id = bank_id
end
def self.card_number
##card_number
end
def create_card_number
##card_number += 1
end
bc = BankComputer.new(100)
puts bc.bank_id
puts BankComputer.card_number
end
The second class:
include BankComputer.rb
class ATMSystem
def show_start_menu
bank_computer_1 = BankComputer.new(1)
end
system = ATMSystem.new()
system.show_start_menu
end
Both classes are in the same directory.
Why doesn't "include BankComputer.rb" work?
How do I import this class correctly?
I found the answer, all you have to do is
require './ClassName'
I have a module in app/misc/dsl/builder.rb that has this code
module Dsl
class Builder
def initialize(context, &block)
return if not block_given?
parent_context = block.binding.eval "self"
parent_context.extend Proxy
parent_context.object = context
parent_context.instance_eval &block
end
end
def self.set_context(context, &block)
Dsl::Builder.new(context, &block)
end
end
Note: this directory misc is preloaded in application.rb
config.autoload_paths += Dir[Rails.root.join('app', 'models', '{**/}'),
Rails.root.join('app', 'misc', '{**/}')
]
Then, somewhere in the text (lets say at foo.rb) I have this code:
Dsl.set_context(obj) do
#some code with obj receiving messages
end
The test stack we are using consists on Zeus+Guard+Rspec. Now, lets say I rewrite the code to something not working
Dsl.set_context(obj) do
asdqwe #this message does not exists
end
From times to times, I receive this baffling message
1) SomeOtherClass search_hash receiving keywords params should query for those keywords
Failure/Error: subject.search_hash
NoMethodError:
undefined method `set_context' for Dsl:Module
# ./app/misc/product_query.rb:116:in `base_search_hash'
# ./app/misc/product_query.rb:25:in `search_hash'
# ./spec/misc/product_query_spec.rb:78:in `block (4 levels) in <top (required)>'
# -e:1:in `<main>'
instead of the correct message that should be regarding undefined method asdqwe
Any clue about this?
Look here
it says:
Rails 3 has been updated such that classes/modules (henceforth, C/M)
are lazy loaded from the autoload paths as they are needed
so, you can do require_relative 'app/misc/dsl/builder.rb' in your rspec_helper.rb (can it be better with just require?) The problem must be that the loader doesn't know in advance where to find Dsl.set_context, but he will know once you have referenced Dsl::Builder
Hope it helps