I'm implementing page objects, and writing tests to verify them. I want to simplify the tests by storing the element names in an array of symbols and looping through it, but it's failing.
def setup
#browser = Watir::Browser.new :phantomjs
#export_page = ExportPage.new #browser
#assets = %i{:section :brand}
end
--
#PASSES
def test_static
$stdout.puts :section.object_id
raise PageElementSelectorNotFoundException, :section unless #export_page.respond_to? :section
end
> # 2123548
This passes because the target class does implement this method, however:
#FAILS
def test_iterator
#assets.each do |selector|
$stdout.puts selector.class
$stdout.puts selector.object_id
$stdout.puts :section.object_id
raise PageElementSelectorNotFoundException, selector unless #export_page.respond_to? selector
end
end
> # Testing started at 11:19 ...
> # Symbol
> # 2387188
> # 2123548
PageElementSelectorNotFoundException: :section missing from page
~/src/stories/test/pages/export_page_test.rb:20:in `block in test_iterator'
As you can see, I've checked the object ids of the symbols and they do seem to be different. Could this be why it's failing? Is there a solution to this?
When using short notation to declare an array of atoms, one should not put colons there:
- %i{:section :brand} # incorrect
+ %i{section brand} # correct
What you have actually defined by #assets = %i{:section :brand}, is the following array:
[:':section', :':brand']
Don't use the %i{} notation, because it automatically makes a symbol of the literal(s) that you specify.
This translates to:
#assets = [:":section", :":brand"]
which is technically an array of symbols, just not the symbols that you intended. This is why the object IDs don't match in your tests.
The %i{} syntax was added in Ruby 2.0. When used in code that may support for older Ruby versions, use a traditional array of symbols:
#assets = [:section, :brand]
Related
I would like to know whether I can get source code a method on the fly, and whether I can get which file is this method in.
like
A.new.method(:a).SOURCE_CODE
A.new.method(:a).FILE
Use source_location:
class A
def foo
end
end
file, line = A.instance_method(:foo).source_location
# or
file, line = A.new.method(:foo).source_location
puts "Method foo is defined in #{file}, line #{line}"
# => "Method foo is defined in temp.rb, line 2"
Note that for builtin methods, source_location returns nil. If want to check out the C source code (have fun!), you'll have to look for the right C file (they're more or less organized by class) and find the rb_define_method for the method (towards the end of the file).
In Ruby 1.8 this method does not exist, but you can use this gem.
None of the answers so far show how to display the source code of a method on the fly...
It's actually very easy if you use the awesome 'method_source' gem by John Mair (the maker of Pry):
The method has to be implemented in Ruby (not C), and has to be loaded from a file (not irb).
Here's an example displaying the method source code in the Rails console with method_source:
$ rails console
> require 'method_source'
> I18n::Backend::Simple.instance_method(:lookup).source.display
def lookup(locale, key, scope = [], options = {})
init_translations unless initialized?
keys = I18n.normalize_keys(locale, key, scope, options[:separator])
keys.inject(translations) do |result, _key|
_key = _key.to_sym
return nil unless result.is_a?(Hash) && result.has_key?(_key)
result = result[_key]
result = resolve(locale, _key, result, options.merge(:scope => nil)) if result.is_a?(Symbol)
result
end
end
=> nil
See also:
https://rubygems.org/gems/method_source
https://github.com/banister/method_source
http://banisterfiend.wordpress.com/
Here is how to print out the source code from ruby:
puts File.read(OBJECT_TO_GET.method(:METHOD_FROM).source_location[0])
Without dependencies
method = SomeConstant.method(:some_method_name)
file_path, line = method.source_location
# puts 10 lines start from the method define
IO.readlines(file_path)[line-1, 10]
If you want use this more conveniently, your can open the Method class:
# ~/.irbrc
class Method
def source(limit=10)
file, line = source_location
if file && line
IO.readlines(file)[line-1,limit]
else
nil
end
end
end
And then just call method.source
With Pry you can use the show-method to view a method source, and you can even see some ruby c source code with pry-doc installed, according pry's doc in codde-browing
Note that we can also view C methods (from Ruby Core) using the
pry-doc plugin; we also show off the alternate syntax for show-method:
pry(main)> show-method Array#select
From: array.c in Ruby Core (C Method):
Number of lines: 15
static VALUE
rb_ary_select(VALUE ary)
{
VALUE result;
long i;
RETURN_ENUMERATOR(ary, 0, 0);
result = rb_ary_new2(RARRAY_LEN(ary));
for (i = 0; i < RARRAY_LEN(ary); i++) {
if (RTEST(rb_yield(RARRAY_PTR(ary)[i]))) {
rb_ary_push(result, rb_ary_elt(ary, i));
}
}
return result;
}
I created the "ri_for" gem for this purpose
>> require 'ri_for'
>> A.ri_for :foo
... outputs the source (and location, if you're on 1.9).
GL.
-r
Internal methods don't have source or source location (e.g. Integer#to_s)
require 'method_source'
User.method(:last).source
User.method(:last).source_location
I had to implement a similar feature (grab the source of a block) as part of Wrong and you can see how (and maybe even reuse the code) in chunk.rb (which relies on Ryan Davis' RubyParser as well as some pretty funny source file glomming code). You'd have to modify it to use Method#source_location and maybe tweak some other things so it does or doesn't include the def.
BTW I think Rubinius has this feature built in. For some reason it's been left out of MRI (the standard Ruby implementation), hence this hack.
Oooh, I like some of the stuff in method_source! Like using eval to tell if an expression is valid (and keep glomming source lines until you stop getting parse errors, like Chunk does)...
I am using the "stock quote" gem (https://github.com/tyrauber/stock_quote) to retrieve stock prices based on user input tickers. While I have a ticker list that is up-to-date, there are some circumstances where the search yields no results. I have this in my code to get the quote:
#companyname = StockQuote::Stock.quote(#ticker).company
#exchange = StockQuote::Stock.quote(#ticker).exchange
#price = StockQuote::Stock.quote(#ticker).last
And it yields this when #ticker = "AKO-A"
undefined method `attributes' for nil:NilClass
file: stock.rb location: block in parse line: 90
Is there anyway to avoid this nomethoderror by making my code more robust (if error then "blank")? Sorry, I am relatively new to ruby and would appreciate any help to point me in the right direction.
Yeah, the problem was definitely with the gem. It was assuming the symbol was accurate and wasn't properly parsing responses for bad symbols.
Sloppy. Rewrote the classes for cleaner code and greater stability. Added in a response_code instance method, which returns 200 or 404, depending upon the validity of the response. Also, a success? or failure? instance method. And, better spec coverage.
Version bumped, and pushed to rubygems.
This is a very common condition with Ruby code, and a common idiom to return nil on a failed search.
However this specific gem is a little flaky when it fails to get a good search result. You can protect yourself against it failing by using a begin ... rescue block.
begin
stock_quote = StockQuote::Stock.quote(#ticker)
rescue StandardError
stock_quote = nil
end
if stock_quote
#companyname = stock_quote.company
#exchange = stock_quote.exchange
#price = stock_quote.last
end
This might not be ideal program flow for you, so you may need to adapt this.
Note StandardError is what gets rescued by default, I didn't need to write that. You could also put NoMethodError in your situation, and usually you want to restrict rescuing exceptions to specific parts of code where you know how to recover from the error, and also only to the types of errors where you are confident that your handling code is doing the right thing.
Here is an example on how use rescue to get around the nonexistent stock symbol problem
require 'stock_quote'
class StockClass
def self.symbol_check(symbol)
StockQuote::Stock.quote(symbol).symbol
end
def self.price_by_symbol(symbol)
StockQuote::Stock.quote(symbol).latest_price
end
def self.write_price_by_symbol(symbol, price)
filename = "#{symbol}.csv"
todays_date = Time.now.strftime('%Y-%m-%d')
File.open(filename, "a") do |file|
file << "#{todays_date}, #{price}\n"
end
end
end
def stock_price_selector(*symbol_array)
symbol_array.each do |stock_name|
begin
stock_check = StockClass.symbol_check(stock_name)
rescue NoMethodError
puts "#{stock_name} is a bogus ticker symbol"
else
stock_price = StockClass.price_by_symbol(stock_name)
stock_written = StockClass.write_price_by_symbol(stock_name, stock_price)
end
end
end
stock_price_selector('AAPL', 'APPL', 'MSFT', 'GOOG')
This will skip the bogus symbol 'APPL' and work for the legtimate ticker symbols.
ruby-docs.org tutorial has section on Modules where the concept of Mixins are introduced.
The example given references the first argument as a string and prints it. But I see in the code that there is no receiver for the argument and execution does fail with ArgumentError
# Ruby module Mixin example.
module Debug
def whoAmI?
"#{self.type.name} (\##{self.id}): #{self.to_s}"
end
end
class Phonograph
include Debug
# ...
end
class EightTrack
include Debug
# ...
end
ph = Phonograph.new("West End Blues")
et = EightTrack.new("Surrealistic Pillow")
ph.whoAmI? #» "Phonograph (#537766170): West End Blues"
et.whoAmI? #» "EightTrack (#537765860): Surrealistic Pillow"
My question is what is proper way to fix this code? Also, if someone can enlighten, how come the example in tutorial is wrong. Did anything change between the versions of ruby?
[tw-mbp13-skumaran ruby]$ ruby ruby23.rb
ruby23.rb:16:in initialize': wrong number of arguments (1 for 0) (ArgumentError)
from ruby23.rb:16:innew'
from ruby23.rb:16
The # ... indicates several missing methods in the code. Try this: https://gist.github.com/3353490
I'm analyzing some code and I'm looking for string literals, to check if I have any duplicates. For example, if I have
def test_foo
input_filename = "foo.txt"
# ...
end
def test_bar
input_filename = "bar.txt" # Fine
# ...
end
def test_baz
# Bad! Refactor it to a constant that's shared by test_foo and test_baz
input_filename = "foo.txt"
# ...
end
I want the analysis program to tell me that ["foo.txt", "bar.txt", "foo.txt"] exist in my source code.
How can I do this?
If you install ruby_parser or parsetree, you'll be able to do something like this (assuming that the program text is in text):
result = RubyParser.new.parse(text)
result.flatten.to_a.select {|elt| elt.is_a?(String)}
(This could obviously be nicer, but it should be enough to get you started!)
I would like to know whether I can get source code a method on the fly, and whether I can get which file is this method in.
like
A.new.method(:a).SOURCE_CODE
A.new.method(:a).FILE
Use source_location:
class A
def foo
end
end
file, line = A.instance_method(:foo).source_location
# or
file, line = A.new.method(:foo).source_location
puts "Method foo is defined in #{file}, line #{line}"
# => "Method foo is defined in temp.rb, line 2"
Note that for builtin methods, source_location returns nil. If want to check out the C source code (have fun!), you'll have to look for the right C file (they're more or less organized by class) and find the rb_define_method for the method (towards the end of the file).
In Ruby 1.8 this method does not exist, but you can use this gem.
None of the answers so far show how to display the source code of a method on the fly...
It's actually very easy if you use the awesome 'method_source' gem by John Mair (the maker of Pry):
The method has to be implemented in Ruby (not C), and has to be loaded from a file (not irb).
Here's an example displaying the method source code in the Rails console with method_source:
$ rails console
> require 'method_source'
> I18n::Backend::Simple.instance_method(:lookup).source.display
def lookup(locale, key, scope = [], options = {})
init_translations unless initialized?
keys = I18n.normalize_keys(locale, key, scope, options[:separator])
keys.inject(translations) do |result, _key|
_key = _key.to_sym
return nil unless result.is_a?(Hash) && result.has_key?(_key)
result = result[_key]
result = resolve(locale, _key, result, options.merge(:scope => nil)) if result.is_a?(Symbol)
result
end
end
=> nil
See also:
https://rubygems.org/gems/method_source
https://github.com/banister/method_source
http://banisterfiend.wordpress.com/
Here is how to print out the source code from ruby:
puts File.read(OBJECT_TO_GET.method(:METHOD_FROM).source_location[0])
Without dependencies
method = SomeConstant.method(:some_method_name)
file_path, line = method.source_location
# puts 10 lines start from the method define
IO.readlines(file_path)[line-1, 10]
If you want use this more conveniently, your can open the Method class:
# ~/.irbrc
class Method
def source(limit=10)
file, line = source_location
if file && line
IO.readlines(file)[line-1,limit]
else
nil
end
end
end
And then just call method.source
With Pry you can use the show-method to view a method source, and you can even see some ruby c source code with pry-doc installed, according pry's doc in codde-browing
Note that we can also view C methods (from Ruby Core) using the
pry-doc plugin; we also show off the alternate syntax for show-method:
pry(main)> show-method Array#select
From: array.c in Ruby Core (C Method):
Number of lines: 15
static VALUE
rb_ary_select(VALUE ary)
{
VALUE result;
long i;
RETURN_ENUMERATOR(ary, 0, 0);
result = rb_ary_new2(RARRAY_LEN(ary));
for (i = 0; i < RARRAY_LEN(ary); i++) {
if (RTEST(rb_yield(RARRAY_PTR(ary)[i]))) {
rb_ary_push(result, rb_ary_elt(ary, i));
}
}
return result;
}
I created the "ri_for" gem for this purpose
>> require 'ri_for'
>> A.ri_for :foo
... outputs the source (and location, if you're on 1.9).
GL.
-r
Internal methods don't have source or source location (e.g. Integer#to_s)
require 'method_source'
User.method(:last).source
User.method(:last).source_location
I had to implement a similar feature (grab the source of a block) as part of Wrong and you can see how (and maybe even reuse the code) in chunk.rb (which relies on Ryan Davis' RubyParser as well as some pretty funny source file glomming code). You'd have to modify it to use Method#source_location and maybe tweak some other things so it does or doesn't include the def.
BTW I think Rubinius has this feature built in. For some reason it's been left out of MRI (the standard Ruby implementation), hence this hack.
Oooh, I like some of the stuff in method_source! Like using eval to tell if an expression is valid (and keep glomming source lines until you stop getting parse errors, like Chunk does)...