Why does the Test.foo work, but Test2.foo? fail.
It seems it works without the '?', but I would prefer to have the ? to follow conversation that it's a boolean.
syntax error, unexpected tOP_ASGN
Works:
class Test
def foo
#foo ||= true # => true
end # => :foo
end # => :foo
FAILS:
class Test2
def foo?
#foo? ||= true # => true
end # => :foo
end # => :foo
? symbol is allowed at the end of a method name but #foo is an instance variable, not a method. And ? is not allowed in variables names
Related
Why won't my module load properly when I include it in my presenter class?
My class methods and module methods are not available when loading from rails. The module works when loading out of rails in a single file.
app/presenters/body_parts/method_wrapper.rb
module BodyParts
def self.included(klass)
klass.extend ClassMethods # => Car
end # => :included
module ClassMethods
def set_wheels(*args)
x, *wheel_args = args # => [3], [3]
puts "Wheels class method called with: #{x.to_s}" # => nil, nil
#wheels |= x # => true, true
end # => :set_wheels
class MethodWrapper
attr_reader :klass # => nil
def initialize(klass)
#klass = klass
end # => :initialize
def wrap(method_name)
puts "Wrapping a method"
wrapper_callback(result)
end # => :wrap
end # => :wrap
end # => :wrap
private # => BodyParts
def wrapper_callback(result)
"Wrapped a #{result} in the call back"
end # => :wrapper_callback
end # => :wrapper_callback
app/presenters/car_presenter.rb
class CarPresenter
include BodyParts # => Car
set_wheels 3 # => true
def brand
'Car Brand' # => "Car Brand"
end # => :brand
set_wheels 3 # => true
def title # policy set to 2 for title methods because of the above
'Car Title'
end # => :title
end # => :title
car_presenter = CarPresenter.new # => #<CarPresenter:0x00fe4ed9300>
car_presenter.brand # => "Car Brand"
# >> Wheels class method called with: 3
# >> Wheels class method called with: 3
Binding.pry from CarsPresenter in Rails
[1] pry(CarPresenter)> set_wheels 3
NameError: undefined local variable or method `set_wheels' for CarPresenter:Class
from (pry):12:in `<class:CarPresenter>'
[2] pry(CarPresenter)> BodyParts
=> BodyParts
[3] pry(CarPresenter)> self
=> CarPresenter
Due to the way const loading works in rails, a module BodyParts should be defined in the top level of presenters directory, i.e. in app/presenters/body_parts.rb.rb.
Rails expects app/presenters/body_parts/method_wrapper.rb to define const BodyParts::MethodWrapper,
Read mode in rails guides.
Hi!
I am expecting #<PrettyThing:0x0055a958175348 #success="anything here">
but I am getting 'anything here' instead. Any idea why?
class Thing
attr_accessor :success
def execute
self.success = execute!
rescue
self.success = false
ensure
self
end
end
class PrettyThing < Thing
def execute!
'anything here'
end
end
p PrettyThing.new.execute # => 'anything here'
Ensure is a tricky thing. Normally, it doesn't return a value, and instead the return value from the last executed line of the main or rescue block is returned, unless there was an uncaught error, then the error is returned. But, if you explicitly return, then you will get the return value. This is a bit nonstandard and confusing though, because the intent of the ensure clause is for silent cleanup. It may be better to move your return value outside your begin/rescue block.
Try:
class Thing
attr_accessor :success
def execute
self.success = execute!
self
rescue
self.success = false
end
end
class PrettyThing < Thing
def execute!
'anything here'
end
end
p PrettyThing.new.execute # => <PrettyThing:0x0000000379ea48 #success="anything here">
The way you have it written, execute is returning the assignment result of self.success = execute!. By adding self, you return the instance of PrettyThing.
This is handy if you want to chain methods, like:
class Thing
attr_accessor :success
def execute
self.success = execute!
self
rescue
self.success = false
end
def foo
puts 'foo'
end
end
class PrettyThing < Thing
def execute!
'anything here'
end
end
p PrettyThing.new.execute.foo # => foo
Given your comment, I think I'd probably do it something more like:
class Thing
attr_accessor :success
alias success? success
def foo
puts 'foo'
end
end
class PrettyThing < Thing
def execute
#success = everything_worked
self
end
private
def everything_worked
# your logic goes here
# return true if all is good
# return false or nil if all is not good
true
end
end
pretty_thing = PrettyThing.new.execute
p pretty_thing.success? # => true
If everything_worked returns false or nil, then pretty_thing.success? will also return false or nil.
My objective is to dynamically load a set of methods to an ActiveRecord model instance based on an attribute that's set:
class Book < ActiveRecord::Base
after_initialize do |cp|
self.class.include "#{cp.subject}".constantize
end
end
I then have the following concerns:
module Ruby
extend ActiveSupport::Concern
def get_framework
'rails'
end
end
module Python
extend ActiveSupport::Concern
def get_framework
'django'
end
end
Then, when I run these separately, I get the correct framework string:
python_book = Book.create(:subject => 'python', :id => 1)
python_book.get_framework -> 'django'
ruby_book = Book.create(:subject => 'ruby', :id => 2)
ruby_book.get_framework -> 'rails'
My problem is that when I have both of the books returned in a query, the Concern is included is the last in the result set and is not picking up the correct Concern methods.
Books.all.order(:id => 'asc').collect do |book|
puts book.get_framework
end
# Result
['rails', 'rails']
I am assuming that this is because the 'include' is happening at the class level and not the instance level. Would love some help as to how to clean this up and make this work.
Use .extend
to add instance methods to a instances of Book instead.
Extends in action:
module Greeter
def say_hello
"Hello"
end
end
irb(main):008:0> a = Object.new
=> #<Object:0x00000101e01c38>
irb(main):009:0> a.extend(Greeter)
=> #<Object:0x00000101e01c38>
irb(main):010:0> a.say_hello
=> "Hello"
irb(main):011:0> Object.new.say_hello
NoMethodError: undefined method `say_hello' for #<Object:0x00000101e196d0>
class Book < ActiveRecord::Base
after_initialize do |cp|
self.extend subject.constantize
end
end
in the following code I am running into an error which states syntax error, unexpected '\n', expecting :: or '[' or '.' (SyntaxError) But I don't see where the issue is.
module Xaaron
class ApiKey.class_eval # It does not like this....
include Promiscuous::Publisher
publish :xaaron_users_id, :api_key, :as => :ApiKey
end
end
Am I using class_eval wrong?
You can either remove the class keyword, and add do after calling class_eval (passing it a block):
module Xaaron
ApiKey.class_eval do
include Promiscuous::Publisher
publish :xaaron_users_id, :api_key, :as => :ApiKey
end
end
(given that ApiKey already exists)
OR you can remove the class_eval altogether:
module Xaaron
class ApiKey
include Promiscuous::Publisher
publish :xaaron_users_id, :api_key, :as => :ApiKey
end
end
This will work even if the ApiKey already exists... that's just the way ruby works...
I want to create a custom method, which I have defined in my questions_controller.rb file, as so:
def self.ping
#question = Question.first
#question.update(:amplify => #question.amplify + 1)
end
Now the problem is how do I call this method? Do I need to define a route first? How can I reference this from the console?
Thanks in advance.
I'd suggest to move it to your model:
question.rb
def self.ping
question = Question.first
question.update(:amplify => question.amplify + 1)
end
and define custom route, routes.rb
post '/ping' => 'questions#ping', as: 'ping'
questions_controller.rb
def ping
Question.ping
end
then you can reference it from console:
Question.ping
Please read this http://www.railstips.org/blog/archives/2009/05/11/class-and-instance-methods-in-ruby/
class Foo
def self.bar
puts 'class method'
end
def baz
puts 'instance method'
end
end
Foo.bar # => "class method"
Foo.baz # => NoMethodError: undefined method ‘baz’ for Foo:Class
Foo.new.baz # => instance method
Foo.new.bar # => NoMethodError: undefined method ‘bar’
Instead of
question.update(:amplify => question.amplify + 1)
You can use
question.increment!(:amplify)