With the following code
class User < ActiveRecord::Base
# ...
# code filtered from here
# ...
# both methods below are public methods
def humanized_roles
roles.collect {|e| e.name.humanize }.join(', ')
end
def role=( arg = nil)
self.roles = []
self.add_role arg.to_sym
end
end
This is happening
User.new.respond_to? :humanized_roles
# => false
User.new.respond_to? "role=".to_sym
# => true
rvm, ruby, rails versions
rvm 1.26.3
ruby 1.9.3p448 (2013-06-27 revision 41675) [x86_64-linux]
Rails 3.2.14
Am I missing something obvious?
In the interest of product release, I circumvented this issue and used a helper method to accept user object as parameter, instead of user.humanize_roles
Thank you everyone for your valuable time & responses.
Related
I have a ruby script for yaml merging as follows
#!/usr/bin/env ruby
require 'yaml'
raise "wrong number of parameters" unless ARGV.length == 2
y1 = YAML.load_file(ARGV[0]).symbolize_keys
y2 = YAML.load_file(ARGV[1]).symbolize_keys
puts y1.merge!(y2).to_yaml
when I execute it:
./test.rb ./src/api/config/config1.yml ./src/api/config/config2.yml
I've got the following error:
./test.rb:5:in `<main>': undefined method `symbolize_keys' for {"root"=>{"cloud.n2"=>{"accessKey"=>"I5VAJUYNR4AAKIZDH777"}}}:Hash (NoMethodError)
Hash#symbolize_keys method comes from activesupport gem (activesupport/lib/active_support/core_ext/hash/keys.rb).
In order to use it, you need to add the following line to your script:
require "active_support"
While the other answers/comments are correct it seems like overkill to require all of ActiveSupport for this. Instead either use:
require 'active_support/core_ext/hash/keys'
Or if you have control over the yml files then just make the keys symbols there and avoid any transformation. For Example
require 'yaml'
yml = <<YML
:root:
:cloud.n2:
:accessKey: "I5VAJUYNR4AAKIZDH777"
YML
YAML.load(yml)
#=> {:root=>{:"cloud.n2"=>{:accessKey=>"I5VAJUYNR4AAKIZDH777"}}}
This does not really the answer your question, but Ruby 2.5.0 introduced Hash#transform_keys (release notes) which also can be used to symbolize keys and is in core Ruby.
{'a' => 1, 'b' => 2}.transform_keys(&:to_sym)
#=> {:a=>1, :b=>2}
There is also a bang version which mutates the hash instead of creating a new one.
As other have already noted, symbolize_keys is an ActiveSupport method. If you are not using ActiveSupport, and/or on a pre-2.5 version of Ruby that does not include transform_keys, you could define it yourself.
class Hash
def transform_keys
return enum_for(:transform_keys) unless block_given?
result = self.class.new
each_key do |key|
result[yield(key)] = self[key]
end
result
end
def transform_keys!
return enum_for(:transform_keys!) unless block_given?
keys.each do |key|
self[yield(key)] = delete(key)
end
self
end
def symbolize_keys
transform_keys{ |key| key.to_sym rescue key }
end
def symbolize_keys!
transform_keys!{ |key| key.to_sym rescue key }
end
end
This is not to say that there are not likely other dependencies on Rails or ActiveSupport that will be required for your script.
My goal is to find the place where save_attachments_to is called in this gmail gem readme example:
folder = "/where/ever"
gmail.mailbox("Faxes").emails do |email|
if !email.message.attachments.empty?
email.message.save_attachments_to(folder)
end
end
I run a "puts email.message.attachments.methods and a "email.message.attachments.class" in the loop:
Mail::AttachmentsList
guess_encoding
set_mime_type
inspect
Then I run a "puts email.message.methods and a "puts email.message.class" for good measure. The example method call is not in the list.
So I go diving into https://github.com/nu7hatch/gmail/blob/master/lib/gmail/message.rb.
No methods are defined there either, but I notice that mime/message is defined, so I go over there to look at its methods: http://rubydoc.info/gems/mime/0.1/MIME/Message
There is no save_attachments_to method here either.
Where the deuce is this method? The gmail gem does not define attachment methods, so the whole thing must be inherited from somewhere. Where? And where's the call that inherits it?
The reason you can't find it is because it doesn't exist. I'm not sure why. I downloaded the gem and played with it for a while in irb:
1.9.3-p194 :066 > x.message.attachments
=> [#<Mail::Part:70234804200840, Multipart: false, Headers: <Content-Type: application/vnd.ms-excel; name="MVBINGO.xls">, <Content-Transfer-Encoding: base64>, <Content-Disposition: attachment; filename="MVBINGO.xls">, <Content-Description: MVBINGO.xls>>]
1.9.3-p194 :063 > x.message.save_attachments_to(folder)
NoMethodError: undefined method `save_attachments_to' for #<Mail::Message:0x007fc1a3875818>
from /Users/Qsario/.rvm/gems/ruby-1.9.3-p194/gems/mail-2.4.4/lib/mail/message.rb:1289:in `method_missing'
from (irb):63
from /Users/Qsario/.rvm/rubies/ruby-1.9.3-p194/bin/irb:16:in `<main>'
Not very helpful. Ordinarily, you can do something like
puts my_obj.method(:some_method_name).source_location
But when the method in question does not exist, that won't help you very much. EDIT: Now that I look, this exact bug is already on their issue tracker. A few people have posted code to implement the non-existent function, such as this code by a-b:
folder = Dir.pwd # for example
email.message.attachments.each do |f|
File.write(File.join(folder, f.filename), f.body.decoded)
end
Thanks for the sanity check Qsario. :-)
Here is code that works in Ruby 1.9.3 (1.9.3-p194):
gmail = Gmail.connect('username#gmail.com', 'pass')
gmail.inbox.emails.each do |email|
email.message.attachments.each do |f|
File.write(File.join(local_path, f.filename), f.body.decoded)
end
end
Here is code that works in 1.9.2 (1.9.2-p320) and 1.9.3 (1.9.3-p194):
gmail = Gmail.connect('username#gmail.com', 'pass')
gmail.inbox.emails.each do |email|
email.message.attachments.each do |file|
File.open(File.join(local_path, "name-of-file.doc or use file.filename"), "w+b", 0644 ) { |f| f.write file.body.decoded }
end
end
I want to understand how Ruby method methods() work.
I tried to Google with "ruby methods" but it's not what i need.
Also i've seen ruby-doc.org, but i didn't find this method.
Can you expain me how it works in details or give me a link?
Update
I experimented with methods() method and got such results:
'lab rat' code
class First
def first_instance_mymethod
end
def self.first_class_mymethod
end
end
class Second < First
def second_instance_mymethod
end
def self.second_class_mymethod
end
end
Work with Classes
#returns available methods list for class and ancestors
puts Second.methods.grep(/mymethod/)
# => second_class_mymethod
# => first_class_mymethod
#returns Class methods list for current class only
puts Second.methods(false)
# => second_class_mymethod
Work with Objects
obj = Second.new
def obj.obj_singleton_mymethod
end
#returns available methods list for object and ancestors
puts obj.methods.grep(/mymethod/)
# => second_instance_mymethod
# => first_instance_mymethod
#returns current object class methods
puts obj.methods(false)
# => obj_singleton_mymethod
The accepted answer misses a slight point. A fuller answer was given in the comment by keymone - .methods returns an array of symbols being names of all the methods defined on the given instance. For example:
irb(main):012:0> object = ""
=> ""
irb(main):013:0> object.instance_eval("def foo;:bar;end")
=> nil
irb(main):014:0> object.methods.include?(:foo)
=> true
irb(main):016:0> "".methods.include?(:foo)
=> false
I'm not entirely sure why it's not in the ruby 1.9 docs (it seems to still be in the code), but you can see the documentation in the 1.8.7 docs: http://www.ruby-doc.org/core-1.8.7/classes/Object.html#M000032
Basically, in ruby 1.9 it just returns a list of the symbols (names) for all the methods in a given class and its ancestors. (ruby 1.8 it returned a list of strings)
I'm on Ruby 2.2.5 and I am unfortunately not getting this to work when passed false any longer. I do remember back on older versions of Ruby, passing false to this method used to return only the class-level methods.
However, as of Ruby 2.2.5, here's what I'm getting
class Thingy < ApplicationRecord
def hello
end
end
class Apple < Thingy
def self.goodbye
end
def booty
end
end
results:
2.2.5 :001 > a = Thingy.new
=> #<Thingy id: nil, created_at: nil, updated_at: nil>
2.2.5 :002 > a.methods(false)
=> []
2.2.5 :003 > b = Apple.new
=> #<Apple id: nil, created_at: nil, updated_at: nil>
2.2.5 :004 > b.methods(false)
=> []
2.2.5 :005 > Apple.methods(false)
=> [:attribute_type_decorations, :_validators, :defined_enums, :goodbye]
2.2.5 :006 > Thingy.methods(false)
=> [:attribute_type_decorations, :_validators, :defined_enums]
2.2.5 :007 >
the only time passing false returns anything interesting to me is to examine class-level methods only (those that start with self.) Otherwise it seems to not be helpful anymore.
I'm trying to use the google_search ruby library (code follows) but it complains that 'cattr_accessor is an undefined method' - any ideas why this might be or how I could fix it?
require 'rubygems'
require 'google_search'
GoogleSearch.web :q => "pink floyd"
cattr_accessor seems to be a Rails extension that acts like attr_accessor, but is accessible on both the class and its instances.
If you want to copy the source of the cattr_accessor method, check out this documentation:
# File vendor/rails/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb, line 46
def cattr_accessor(*syms)
cattr_reader(*syms)
cattr_writer(*syms)
end
# File vendor/rails/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb, line 4
def cattr_reader(*syms)
syms.flatten.each do |sym|
next if sym.is_a?(Hash)
class_eval("unless defined? ##\#{sym}\n##\#{sym} = nil\nend\n\ndef self.\#{sym}\n##\#{sym}\nend\n\ndef \#{sym}\n##\#{sym}\nend\n", __FILE__, __LINE__)
end
end
# File vendor/rails/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb, line 24
def cattr_writer(*syms)
options = syms.extract_options!
syms.flatten.each do |sym|
class_eval("unless defined? ##\#{sym}\n##\#{sym} = nil\nend\n\ndef self.\#{sym}=(obj)\n##\#{sym} = obj\nend\n\n\#{\"\ndef \#{sym}=(obj)\n##\#{sym} = obj\nend\n\" unless options[:instance_writer] == false }\n", __FILE__, __LINE__)
end
end
You can get this functionality by including the Ruby Facets gem. Reference the source here:
https://github.com/rubyworks/facets/blob/master/lib/core/facets/cattr.rb
You generally don't need to require all code from the gem. You can selectively require what you want. There are quite a few useful extensions in the gem though.
I have a method that takes a block.
Obviously I don't know what is going to be passed in and for bizarre reasons that I won't go into here I want to print the contents of the block.
Is there a way to do this?
You can do this with Ruby2Ruby which implements a to_ruby method.
require 'rubygems'
require 'parse_tree'
require 'parse_tree_extensions'
require 'ruby2ruby'
def meth &block
puts block.to_ruby
end
meth { some code }
will output:
"proc { some(code) }"
I would also check out this awesome talk by Chris Wanstrath of Github http://goruco2008.confreaks.com/03_wanstrath.html He shows some interesting ruby2ruby and parsetree usage examples.
In Ruby 1.9+ (tested with 2.1.2), you can use https://github.com/banister/method_source
Print out the source via block#source:
#! /usr/bin/ruby
require 'rubygems'
require 'method_source'
def wait &block
puts "Running the following code: #{block.source}"
puts "Result: #{yield}"
puts "Done"
end
def run!
x = 6
wait { x == 5 }
wait { x == 6 }
end
run!
Note that in order for the source to be read you need to use a file and execute the file (testing it out from irb will result in the following error: MethodSource::SourceNotFoundError: Could not load source for : No such file or directory # rb_sysopen - (irb)
Building on Evangenieur's answer, here's Corban's answer if you had Ruby 1.9:
# Works with Ruby 1.9
require 'sourcify'
def meth &block
# Note it's to_source, not to_ruby
puts block.to_source
end
meth { some code }
My company uses this to display the Ruby code used to make carbon calculations... we used ParseTree with Ruby 1.8 and now sourcify with Ruby 1.9.
In Ruby 1.9, you can try this gem which extract the code from source file.
https://github.com/ngty/sourcify
In Ruby 2.5 the following works
puts block.source
In ruby 2.7, using the method_source gem (pry depends on it)
Set.instance_method(:merge).source.display
# =>
def merge(enum)
if enum.instance_of?(self.class)
#hash.update(enum.instance_variable_get(:#hash))
else
do_with_enum(enum) { |o| add(o) }
end
self
end
The repo says it works for procs, but I haven't tested it.