Using a Ruby Module for Defaults - ruby

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

Related

Calling a module function in a ruby module

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.

undefined method for calling methode in class

i try to call my methode check_table_exists for check my table. This methode is on my module, and i dont understand why i get this error .
i know #connexion is a Mysql2::Client instance, which doesn't include the module Sgbd. but i dont see how to include my methode ?
./yamlReadFile.rb:44:in `mysql_connection': undefined method `check_table_exists' for #<Mysql2::Client:0x000000033a7750> (NoMethodError)
$LOAD_PATH << '.'
require 'yaml'
require 'rubygems'
require 'mysql2'
require 'creatDatabase'
#binding.pry
class StreamMysql
include Sgbd
def mysql_connection(conf)
#connexion = Mysql2::Client.new(:host => conf['ost'], :username => conf['user'], :password => conf['password'], :table => conf['table'], :port => conf['port'])
if #connexion
puts check_table_exists
#connexion.check_table_exists
puts "connexion etablie"
else
puts "error connexion"
end
rescue Mysql2::Error => e
puts e.errno
puts e.error
#connexion.close
end
def read_config_file
config = YAML::load_file(File.join(__dir__, 'config.yml'))
conf = config['database']
mysql_connection(conf)
end
end
my module file with the mehode check_table_exists
module Sgbd
# class ModuleCreateDatabase
def create_database
end
def check_table_exists
query=("SHOW TABLES;")
end
end
It’s unclear why would you want to include your module in the foreign class, but it’s doable:
Mysql2::Client.include Sgbd
The line above should be put e. g. before class StreamMysql declaration.

active_record configuration from yaml file: debuglevel

I'm trying to configure the debuglevel for active-record logger from a YAML configuration file but get the following error, how could i do this other than using a number in the YAML ?
sample.rb:30 warning: toplevel constant LEVEL referenced by Logger::LEVEL
"DEBUG"
ArgumentError: comparison of Fixnum with String failed
here is the sample.rb
require 'java'
require 'active_record'
require 'activerecord-jdbc-adapter'
require 'yaml'
require 'logger'
def get_jar_path
if __FILE__[/.+\.jar!/] #in case run from JAR
scriptpath = __FILE__[/(.*)\/.+\.jar!/]
$1[6..-1]
else #in case run with jRuby
'..'
end
end
def load_config
path = "#{get_jar_path}/#{File.basename(__FILE__, ".*")}.configuration.yml"
p path
$conf = YAML::load_file(path)
end
load_config
LEVEL = $conf['debug_level'] #string 'DEBUG' from configuration file
$log = Logger.new( "#{get_jar_path}/log_#{Time.now.strftime("%Y%m%d")}.txt", 'monthly' )
ActiveRecord::Base.logger = $log
ActiveRecord::Base.logger.level = Logger::DEBUG #works
ActiveRecord::Base.logger.level = Logger::LEVEL #doesn't work
p ActiveRecord::Base.logger.level
$log.info "start #{__FILE__}"
The available log levels are: :debug, :info, :warn, :error, :fatal,
and :unknown, corresponding to the log level numbers from 0 up to 5
respectively.
http://guides.rubyonrails.org/debugging_rails_applications.html
require 'logger'
puts Logger::DEBUG
--output:--
0
str = "DEBUG"
puts Logger.const_get(str)
--output:--
0
So you should do something like:
level = $conf['debug_level'] #string 'DEBUG' from configuration file
$log = Logger.new( "#{get_jar_path}/log_#{Time.now.strftime("%Y%m%d")}.txt", 'monthly' )
ActiveRecord::Base.logger = $log
ActiveRecord::Base.logger.level = Logger.const_get(level)
I'm not sure why you thought defining a constant, LEVEL, in the current scope would make that constant appear in the Logger scope, so that you could write Logger::LEVEL. You essentially did this:
MYCONST = "hello"
module SomeModule
SOMECONST = "goodbye"
end
You can write:
puts MYCONST #=>hello
..and you can write:
puts SomeModule::SOMECONST #goodbye
..but you cannot write:
puts SomeModule::MYCONST
--output:--
1.rb:10:in `<main>': uninitialized constant SomeModule::MYCONST (NameError)

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

Why doesn't relative_require work on Ruby 1.8.6?

I'm learning Ruby (using version 1.8.6) on Windows 7.
When I try to run the stock_stats.rb program below, I get the following error:
C:\Users\Will\Desktop\ruby>ruby stock_stats.rb
stock_stats.rb:1: undefined method `require_relative' for main:Object (NoMethodE
rror)
I have three v.small code files:
stock_stats.rb
require_relative 'csv_reader'
reader = CsvReader.new
ARGV.each do |csv_file_name|
STDERR.puts "Processing #{csv_file_name}"
reader.read_in_csv_data(csv_file_name)
end
puts "Total value = #{reader.total_value_in_stock}"
csv_reader.rb
require 'csv'
require_relative 'book_in_stock'
class CsvReader
def initialize
#books_in_stock = []
end
def read_in_csv_data(csv_file_name)
CSV.foreach(csv_file_name, headers: true) do |row|
#books_in_stock << BookInStock.new(row["ISBN"], row["Amount"])
end
end
# later we'll see how to use inject to sum a collection
def total_value_in_stock
sum = 0.0
#books_in_stock.each {|book| sum += book.price}
sum
end
def number_of_each_isbn
# ...
end
end
book_in_stock.rb
require 'csv'
require_relative 'book_in_stock'
class CsvReader
def initialize
#books_in_stock = []
end
def read_in_csv_data(csv_file_name)
CSV.foreach(csv_file_name, headers: true) do |row|
#books_in_stock << BookInStock.new(row["ISBN"], row["Amount"])
end
end
# later we'll see how to use inject to sum a collection
def total_value_in_stock
sum = 0.0
#books_in_stock.each {|book| sum += book.price}
sum
end
def number_of_each_isbn
# ...
end
end
Thanks in advance for any help.
require_relative doesn't exist in your version of Ruby. You could upgrade Ruby, install the backports gem and require 'backports/1.9.1/kernel/require/relative' but the easiest fix will be to change your require to:
require File.join(File.dirname(__FILE__), 'csv_reader')
Edit:
Back in the days where this question was asked it referred to Ruby 1.8.6 where there was no require_relative. By now Ruby 1.8.6 is outdated and shouldn't be used anymore.
Original:
There is simply no method name require_relative. You can use require there aswell.
The require_relative function is included in an extension project to the Ruby core libraries, found here: http://www.rubyforge.org/projects/extensions
You should be able to install them with gem install extensions.
Then in your code add the following line before the require_relative:
require 'extensions/all'

Resources