Calling a module function in a ruby module - ruby

I want to call a module function to define a constant in a utility module in ruby. However, when I try this I get an error message. Here comes the code and the error:
module M
ABC = fun
module_function
def self.fun
"works"
end
end
Error message:
NameError: undefined local variable or method `fun' for M:Module
Any ideas? I also tried it without self and with M.fun but no success...

It is just that the method is not defined when you assign fun to ABC. Just change the order:
module M
def self.fun
"works"
end
ABC = fun
end
M::ABC
#=> "works"
If you dislike the order (constants below methods), you might want to consider to have the method itself to memorize its return value. A common pattern looks like:
module M
def self.fun
#cached_fun ||= begin
sleep 4 # complex calculation
Time.now # return value
end
end
end
M.fun
# returns after 4 seconds => 2017-03-03 23:48:57 +0100
M.fun
# returns immediately => 2017-03-03 23:48:57 +0100

Test this in you irb console:
$ irb
2.3.3 :001 > module M
2.3.3 :002?> def self.fun
2.3.3 :003?> "worked"
2.3.3 :004?> end
2.3.3 :005?>
2.3.3 :006 > ABC = fun
2.3.3 :007?> end
=> "worked"
2.3.3 :008 > M
=> M
2.3.3 :009 > M::ABC
=> "worked"
2.3.3 :010 >
The fact is that now you defined self.fun before using it.
In your code you used the method before defining it.

Related

Responding to one method but not to other in the same scope

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.

Ruby library like Hashie that can use lambdas as properties

Is there a Ruby library that works like Hashie except it can take a lambda as a property and call it when that property is accessed?
For example, I'd like something like this:
# Lash = Lambda-able hash
lash = Lash.new(
someProperty: "Some value",
someOtherProperty: ->{ Time.now }
)
lash.someProperty # => "Some value"
lash.someOtherProperty # => 2013-01-25 16:36:45 -0500
lash.someOtherProperty # => 2013-01-25 16:36:46 -0500
Here's my implementation:
class Lash < BasicObject
def self.new hash
::Class.new do
hash.each do |key, value|
method_body = if value.respond_to? :call
->(*args){ self.instance_exec(*args, &value) }
else
->{ value }
end
define_method(key, &method_body)
end
end.new
end
end
I wanted something similar a few days ago and ended up using Hashie 2.0.0.beta which gives you extensions that you can use with your own subclasses of Hash:
require 'hashie'
require 'hashie/hash_extensions'
class Lash < Hash
include Hashie::Extensions::MethodAccess
def [](key)
val = super(key)
if val.respond_to?(:call) and val.arity.zero?
val.call
else
val
end
end
end
This lets you do things like:
l = Lash.new
#=> {}
l.foo = 123
#=> 123
l.bar = ->{ Time.now }
#=> #<Proc:0x007ffab3915f18#(irb):58 (lambda)>
l.baz = ->(x){ 10 * x }
#=> #<Proc:0x007ffab38fb4d8#(irb):59 (lambda)>
l.foo
#=> 123
l.bar
#=> 2013-01-26 15:36:50 +0100
l.baz
#=> #<Proc:0x007ffab38fb4d8#(irb):59 (lambda)>
l.baz[5]
#=> 50
Note: this only works in Hashie 2.0.0.beta which you can install via Bundler by adding this line to your Gemfile:
gem 'hashie', :git => 'git://github.com/intridea/hashie.git'
or, without Bundler, using the specific_install gem:
gem install specific_install
gem specific_install -l git://github.com/intridea/hashie.git

Using a Ruby Module for Defaults

I'd like to use a Ruby Module to store a set of configuration defaults.
I'm having some problems using the values and hope someone could help.
This may not be the best way to do this but this is what I've come up with so far.
Here is a module to hold value for a persons Resume => resume.rb
module Resume
require 'ostruct'
attr_reader :personal, :education
#personal = OpenStruct.new
#education = Array.new
def self.included(base)
set_personal
set_education
end
def self.set_personal
#personal.name = "Joe Blogs"
#personal.email_address = 'joe.blogs#gmail.com'
#personal.phone_number = '5555 55 55 555'
end
def self.set_education
#education << %w{ School\ 1 Description\ 1 }
#education << %w{ School\ 2 Description\ 2 }
end
end
From irb it works fine:
% irb -I .
1.9.3-p194 :001 > require 'resume'
=> true
1.9.3-p194 :002 > include Resume
=> Object
1.9.3-p194 :003 > puts Resume.personal.name
Joe Blogs
=> nil
However when I include this into a class it throws and error => build.rb
require 'resume'
class Build
include Resume
def build
puts Resume.personal.name
end
end
From irb:
% irb -I .
1.9.3-p194 :001 > require 'build'
=> true
1.9.3-p194 :002 > b = Build.new
=> #<Build:0x00000001d0ebb0>
1.9.3-p194 :003 > b.build
NoMethodError: undefined method `personal' for Resume:Module
from /home/oolyme/projects/lh_resume_builder_ruby/build.rb:7:in `build'
from (irb):3
from /home/oolyme/.rvm/rubies/ruby-1.9.3-p194/bin/irb:16:in `<main>'
I've tried a few variations to output the include module variables in the Build class instance but all error out.
attr_accessor creates a couple of instance methods, meaning that they will be available on an instance of Build. But you clearly want class instance methods. Change definition of your module to this:
module Resume
require 'ostruct'
def self.personal
#personal
end
def self.education
#education
end
def self.included(base)
#personal = OpenStruct.new
#education = Array.new
set_personal
set_education
end
def self.set_personal
#personal.name = "Joe Blogs"
#personal.email_address = 'joe.blogs#gmail.com'
#personal.phone_number = '5555 55 55 555'
end
def self.set_education
#education << %w{ School\ 1 Description\ 1 }
#education << %w{ School\ 2 Description\ 2 }
end
end
And it'll work
b = Build.new
b.build # >> Joe Blogs

Why do I get "stack level too deep" from method_missing in irb 1.9.3?

Scenario:
-bash-3.2$ irb -f
ruby-1.9.3-p0 :001 > #v = {}
=> {}
ruby-1.9.3-p0 :002 > def method_missing(sym, *args); #v[sym]; end
=> nil
ruby-1.9.3-p0 :003 > a
(irb):2: stack level too deep (SystemStackError)
-bash-3.2$
I ran with -f to avoid loading any irbrc stuff.
I'm expecting to get nil when I input a. What's going on, and is there a workaround? I tried wrapping a with a begin/rescue Exception block but that didn't do anything.
This also happens with 1.9.2, but not 1.9.1.
More strange behavior:
-bash-3.2$ irb -f
irb(main):001:0> #v = {}
=> {}
irb(main):002:0> def method_missing(sym, *args); #v[sym]; end; 5.times { p a }
nil
nil
nil
nil
nil
=> 5
irb(main):003:0> a
(irb):2: stack level too deep (SystemStackError)
-bash-3.2$
This tells me that there's a bug in irb, or that some obscure bug in ruby is being triggered by irb. Also, after defining method_missing, even methods that exist like local_variables or eval cause the error.
Looks like defining it as a singleton method works:
def self.method_missing(sym, *args); #v[sym]; end
Defining it as a top-level method replaces BasicObject#method_missing, which probably affected some irb internals like Phrogz said.

Ruby methods() method

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.

Resources