I have a capybara monkey patch to deal with jquery-ui, which works pretty well running on Ubuntu... although when moving to windows I get the following error (all dependency gems were installed successfully):
Undefined method 'delegate' for capybara::dsl::module
The line of code that this occurs is:
module Capybara::DSL
delegate :datepick, :datetimepick, :timepick, to: :page
end
any ideas of what this could be? a bit lost of why this error is shown just by switching OS...
In standard ruby delegation is handled by the module Forwardable. You need to require and then extend Forwardable to access these methods like so:
require 'forwardable'
module Capybara::DSL
extend Forwardable
#notice syntax is accessor, *methods
def_delegators :page, :datepick, :datetimepick, :timepick
end
The type of delegation you are trying to use right now is part of active support Module Class. If you would like to use this syntax then do so like this:
require 'active_support/core_ext/module'
module Capybara::DSL
#active_support syntax allows a to: element in the hash to act as the accessor
delegate :datepick, :datetimepick, :timepick, to: :page
end
Related
I've got NON-RAILS app where I want to include Errors module to Formatter module to access the method error_class from Errors. Like below:
#lib/formatter.rb
module Formatter
module_function
include ::Errors
def format(number)
number.delete!(' ')
raise error_class(:invalid_number), 'Invalid phone number, check your entries' unless valid?(number)
end
end
#lib/errors.rb
module Errors
class FormatterExceptionError < StandardError; end
PhoneNumberInvalid = Class.new(FormatterExceptionError)
def error_class(status)
case status
when :invalid_number
PhoneNumberInvalid
end
end
end
With this code I'm getting an error:
Failure/Error: include ::Errors
NameError:
uninitialized constant Errors
Did you mean? Errno
Non-rails apps doesn't have auto-load classes, so you need to manually require it.
Also one thing of your code, I don't know why you are using :: before constant, I don't see any naming-confusion in order to use it. It is used only when you have your Errors modules on different namespace, and you need to resolve the one from your namespace.
# lib_formatter
require 'errors'
module Formatter
extend Errors
# ...
end
The second issue with your code, that you have defined instance method, but where you include your code there class method (module method)
So errors class should be adjusted to
module Errors
# ...
module_function
# ...
end
The third issue is include/extend misusage.
Include used to make all methods from module you using to become instance methods.
Extend used to make all methods from module you using to become class methods.
include/extend info
I'm using watir-cucumber for test automation. I wrote following method in a separate .rb, this method is not in step definitions.
def has_logged_in?
$browser.text.should include("t788")
end
When I call this method from step definition this error comes,
wrong argument type String (expected Module) (TypeError)
the same code works fine in step definitions. I searched around and found out that include method is used to include module but that is ruby-include method and should include comes under rspec\expectations. So how do I call should include method outside step definition like above.
I'm using watir-cucumber on linux
The include method that you want is in the RSpec::Matchers module.
If your has_logged_in? method is in a class (not part of main), you can include the RSpec::Matchers module in your class. This would give you access to the include method.
So your class would look like:
class YourClass
include RSpec::Matchers
def has_logged_in?
$browser.text.should include("t788")
end
end
Note: I have not had to do this before, but from a quick check, it does work as long as the RSpec::Matchers are included in a class rather than the main. Including it in the main does not appear to do anything (ie include continues to call the standard include module method). I did not explore to see if if there are any negative side effects of doing this.
In your gem file:
gem 'rspec', "1.3.2", :require => "spec/expectations"
Or in your env.rb for RSpec 1.X.X:
require 'spec/expectations'
Or in your env.rb for RSpec 2.X:
require 'rspec/expectations'
[SOLVED: See my comment below]
I've created a Ruby Gem to connect to my application's API: my_app_api. I'd like to use it like so: MyAppAPI::Foo.bar(). However, I get:
NameError: uninitialized constant MyAppAPI
I know the standard way to call/name this would be MyAppApi::Foo.bar(), but I'd prefer to keep with acronym class naming conventions. How do I specify/load the module?
For reference, the class looks like this:
module MyAppAPI
class Foo < ActiveResource::Base
extend MyAppAPI
self.site = 'http://localhost:3000/api/'
self.format = :json
class << self
def bar
return 'huzzah!'
end
end
end
end
And the my_app_api.rb file looks like this:
require "rubygems"
require 'active_resource'
require 'my_app_api/foo'
Have you tried loading the gem the normal way?
require 'my_app_api'
MyAppAPI::Foo.bar()
The constant name MyAppAPI is fine and is not the cause of the problem. There are tons of Ruby core classes/modules that have acronyms in their names:
http://www.ruby-doc.org/core-1.9.3/GC.html
http://www.ruby-doc.org/core-1.9.3/RubyVM.html
http://ruby-doc.org/stdlib-1.9.3/libdoc/csv/rdoc/CSV.html
Try declaring the empty module in my_app_api.rb after your require statements:
module MyAppAPI
end
This may help if you're relying on a dynamic class and module loading mechanism (like Rails uses).
I assume your app is explicitly calling require "my_app_api". What kind of app is this, and where are you doing the require?
I've noticed in some gems, when you simply require 'some_gem', methods will appear (without any monkey patching to my knowledge). I've seen it in some gems like Sinatra, Rake, Rails, and many other helper libraries and such. How would one manage to accomplish this in ones own library?
Example:
require 'sinatra'
# Automatically recieve the 'get' method
get('/') { "I was monkeypatched or included automatically." }
If it is monkeypatching, what classes/modules are common for monkeypatching (other than String, Numeric, Array, etc).
Sinatra is essentially adding those as global methods. When you require sinatra, it extends the Object class with Sinatra::Delegator which is defined in sinatra/base.rb. Methods such as get and put are defined in base, and added via the delegator.
In addition to Beerlington's answer, Rails, for example, and specifically it's part ActiveSupport, uses exactly monkeypatching.
For example, declaration of blank? method from the ActiveSupport source (stripped):
class Object
def blank?
respond_to?(:empty?) ? empty? : !self
end
end
Also, very common approach to monkeypatch Kernel module to add methods that will be available everywhere:
# hello.rb
module Kernel
def say_hello
"Hello!"
end
end
And usage of it:
require 'hello.rb'
=> true
say_hello
=> "Hello!"
I would like to put some code in module that throws an error if certain method is not defined.
This module relies on the external definition of this method, since this method's implementation is different for all classes. This code would help developers know early that they forgot to implement the method rather than when they tried to use features of the module.
module MyModule
def self.included(klass)
raise "MyModule: please `def my_method` on #{klass}" unless klass.respond_to?(:my_method)
end
end
I can easily raise an error in a module's included definition if a method is not defined, however since most modules are included at the top of a file, it's likely that my required method is defined in the class, but not before my module is included.
class MyClass
include MyModule
def self.my_method
# ...
end
end
This would still raise an error :(
Is it possible to raise an error only if the method truly is not defined in the class definition? Almost need a class.onload callback of sorts. If not, any other ideas for how to mitigate the possibilities that a programmer might include our module without defining this needed method?
Sounds like you want to make use of method_missing and define_method.
If you do use method_missing don't forget to:
call super for unhandled cases.
also implement a respond_to? method
look at this question, plus this and that.
Update:
It sounds the goal is to do static method checking like Java or c++ does. This is not really meaningful in ruby :-(
Since in ruby:
Each instance of an object has its own eigenclass. A given object may have the necessary methods mixed in at runtime. So just because Foo does not have a method at class load time is meaningless.
Frameworks like RoR hooks method_missing and dynamically create methods needed for the database query methods, so the method may exist (or not) when it is needed.
With regards to "class on load": A class definition is really executed. Try this:
class Foo
p "Hi"
end
You will see "Hi" the first and only the first time Foo is used. This is how things like devise hook into do their magic.
class User < ActiveRecord::Base
# **CALL 'devise' method**
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable
# **CALL attr_accessible method**
attr_accessible :email, :password, :password_confirmation
end
So maybe by private convention have developers add a check_class method call to the bottom of the classes in question?
I understand the intent but it seems like fighting the way ruby is designed to work.
As a mostly Java person I appreciate the frustration. Let me guess: repeated cases of code getting pushed to production that had missing methods? :-P
Update2:
wrt onload In ruby barring use of frozen a class get new methods defined all the time. ( Or an instance can get new methods defined just for that instance. ) so checking for a method's nonexistence is only a snapshot check and not as definitive a check as a static language brings to the table. This is ruby's very own Halting problem
How about declaring a method with that name, which just raises an error, to make sure the user redefines the method?
module MyModule
def my_method
raise "Please implement me"
end
end
class MyClass
include MyModule
def my_method
# do something
end
end
Assuming your program requires all files when started and does not use any autoload and the like, you could use something like the following right after everything is required, but before the program actually starts:
classes_to_check = Object.constants.find_all do |const|
klass = Object.const_get(c)
klass.ancestors.include?(MyModule) if klass.kind_of?(Module)
end
classes_to_check.each do |klass|
raise "MyModule: please `def my_method` on #{klass}" \
unless klass.respond_to?(:my_method)
end
However, I personally always use Dogbert's solution.