Showing posts with label ruby. Show all posts
Showing posts with label ruby. Show all posts

Friday, August 13, 2010

Benchmarking any rake task

While writing serializable_proc, i wanted to find out how the RubyParser-based implementation fair against ParseTree-based one, here's a rake task i've written to support the following use cases:

# yield benchmark results by running :spec task x5 (default)
$ rake benchmark[spec]

And:

# yield benchmark results by running :spec task x2
$ rake benchmark[spec,2]

And here's the code to acheive the above:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# Benchmarking
task :benchmark, :task, :times do |t, args|
times, task = (args.times || 5).to_i.method(:times), args.task
title = " ~ Benchmark Results for Task :#{task} ~ "
results = [%w{nth}, %w{user}, %w{system}, %w{total}, %w{real}]

# Running benchmarking & collecting results
require 'benchmark'
times.call do |i|
result = Benchmark.measure{ Rake::Task[task].execute }.to_s
user, system, total, real =
result.match(/^\s*(\d+\.\d+)\s+(\d+\.\d+)\s+(\d+\.\d+)\s+\(\s*(\d+\.\d+)\)$/)[1..-1]
["##{i.succ}", user, system, total, real].each_with_index{|val, j| results[j] << val }
end

# Formatting benchmarking results
formatted_results = results.map do |rs|
width = rs.map(&:to_s).map(&:size).max
rs.map{|r| ' ' + r.ljust(width, ' ') }
end.transpose.map{|row| row.join }

# Showdown .. printout
line = '=' * ([title.size, formatted_results.map(&:size).max].max + 2)
puts [line, title, formatted_results.join("\n"), line].join("\n\n")

end

And here's the output i get for the x2 run:

...
(blah blah, the output of running :spec task x2)
...
===============================================

~ Benchmark Results for Task :spec ~

nth user system total real
#1 0.000000 0.000000 1.030000 1.052567
#2 0.000000 0.000000 1.020000 1.040352

===============================================

Friday, August 6, 2010

Reliably getting a formatted time string in ur desired lang

Today, i'm spent quite abit of time playing with the very simple Time#strftime:
1
2
puts Time.now.strftime("%B %d, %Y %H:%M")
# >> August 06, 2010 17:17

What i want to acheive is to reliably get the chinese version:

八月 06, 2010 17:24

I've tried playing with the environment variable $LANG:

$ export LANG=zh_CN.utf8
$ locale
LANG=zh_CN.utf8
LC_CTYPE="zh_CN.utf8"
LC_NUMERIC="zh_CN.utf8"
LC_TIME="zh_CN.utf8"
LC_COLLATE="zh_CN.utf8"
LC_MONETARY="zh_CN.utf8"
LC_MESSAGES="zh_CN.utf8"
LC_PAPER="zh_CN.utf8"
LC_NAME="zh_CN.utf8"
LC_ADDRESS="zh_CN.utf8"
LC_TELEPHONE="zh_CN.utf8"
LC_MEASUREMENT="zh_CN.utf8"
LC_IDENTIFICATION="zh_CN.utf8"
LC_ALL=

Seems good, but nope, Time#strftime still gives me the same english output. I've trying recompiling a different ruby using rvm with the exported $LANG ... nope, doesn't work either. It seems that not matter how $LANG is set (thus affecting LC_TIME), ruby just doesn't care abt it. Yet, i swear that on flyhzm's machine, he has been getting the chinese version, no matter how hard he has tried to get the english version.

Battled, beaten & worn out, i've concluded that the most reliable way (and definitely what most people do), is to use the i18n. Given i already have this /path/to/i18n.yml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
en:
date:
month_names: [~, January, February, March, April, May, June, July, August, September, October, November, December]

time:
formats:
default: "%B %d, %Y %H:%M"

zh:
date:
month_names: [~, 一月, 二月, 三月, 四月, 五月, 六月, 七月, 八月, 九月, 十月, 十一月, 十二月]

time:
formats:
default: "%B %d, %Y %H:%M"

The following works for mri 1.9.1:
1
2
3
4
5
6
7
8
9
10
11
require 'rubygems'
require 'i18n'

I18n.load_path << '/tmp/i18n.yml'
p I18n.available_locales # >> [:en, :zh]

I18n.locale = :en
p I18n.localize(Time.now) # >> "August 06, 2010 17:48"

I18n.locale = :zh
p I18n.localize(Time.now) # >> "八月 06, 2010 17:48"

Without modication, i got the following unfriendly output for the chinese port under mri 1.8.7, jruby & ree-1.8.7:

\345\205\253\346\234\210 06, 2010 20:27

After much googling, stumbled across this post abt $KCODE. Here's the final modified code for the 1.8.7 equivalents:
1
2
3
4
5
6
7
8
9
10
require 'rubygems'
require 'i18n'

$KCODE = 'UTF-8' # Hey, this matters !!

I18n.locale = :en
p I18n.localize(Time.now) # >> "August 06, 2010 17:48"

I18n.locale = :zh
p I18n.localize(Time.now) # >> "八月 06, 2010 17:48"

For people doing rails, here are some useful resources:
* http://guides.rubyonrails.org/i18n.html
* http://github.com/svenfuchs/rails-i18n

Wednesday, August 4, 2010

Bitten by Array#*

Have u tried Array#* ? Its a pretty cool way to return an array, built by concatenating the original array by n times:
1
2
3
4
5
a = [1] * 2
p a # >> [1, 1]

a = %w{a} * 2
p a # >> ["a", "a"]

However, u should be aware that all elements of the new array actually points to the same instance, as proven by their object_id:
1
2
3
4
5
x = 'a'
p x.object_id # >> 70212363949780

a = [x] * 2
p a.map(&:object_id) # >> [70212363949780, 70212363949780]

This means that:
1
2
3
4
5
6
7
8
9
10
11
12
13
# Reassigning one element does not affect another
a = %w{a} * 2
p a.map(&:object_id) # >> [70058328018360, 70058328018360]
a[0] = a[0].sub('a','b')
p a # >> ["b", "a"]
p a.map(&:object_id) # >> [69915340242120, 69915340242360]

# In-place manipulating one element affects another
a = %w{a} * 2
p a.map(&:object_id) # >> [70058328018360, 70058328018360]
a[0].sub!('a','b')
p a # >> ["b", "b"]
p a.map(&:object_id) # >> [70058328018360, 70058328018360]

Wednesday, July 28, 2010

Lazy evaluating with Enumerable#any?

Most of us know this:
1
2
3
4
5
6
7
8
class Awesome
def self.m1 ; true ; end
def self.m2 ; raise Exception ; end
end

# Case 1:
Awesome.m1 or Awesome.m2
# >> no error thrown

For some of us who likes Enumerable#any?, this won't work:
1
2
3
# Case 2:
[Awesome.m1, Awesome.m2].any?
# >> error thrown

That is because :m1 & :m2 are already evaluated before calling Enumerable#any?, to have lazy evaluation, we can do this:
1
2
3
# Case 3:
[:m1, :m2].any?{|m| Awesome.send(m) }
# >> no error thrown

For the perversive ones:
1
2
3
# Case 4:
Awesome.instance_exec { [:m1, :m2].any?{|m| send(m) } }
# >> no error thrown

Thursday, July 22, 2010

Everyone should start writing macros

Did some cleaning & catching up of specs for railsbestpractices.com yesterday, added quite a number of spec macros to dry up stuff, as well as cutting down the complexity within the spec files. Personally, i really really & really like macros, because it is fun to write & easy to write, it has many beneficial side effects:

#1. Since it is so simple to use macros, everyone in the team is more willing to participate in spec writing. Personal experience has proven that if specs/tests are hard to write, some developers tend to skip it.

#2. Since it is so easy to read, maintenance becomes much easier

#3. Developers are smart people (and should be paid well, but that's another story), by replacing repeated copy & paste & minor edit-here-and-there with macros-writing-and-usage, they feel smarter, a huge morale boast ~> happier team, & when people are happy, they tend to show more love towards the project, take ownership ~> project in a better state.

Btw, macro writing is no rocket-science, let's get started:

#1. Macro for 3rd party declarative
1
2
3
4
class User < ActiveRecord::Base
acts_as_authentic
# (blah blah)
end

Ok, we all know that authlogic is well tested, so there is really no point in writing specs for it. Yet, how do we know the model is pulling in authlogic support ?? Here's what i've done:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
module RailsBestPractices
module Macros

def self.included(base)
base.extend(ClassMethods)
end

module ClassMethods

def should_act_as_authentic
# Get most basic modules included by ActiveRecord::Base
basic_included_modules = Class.new(ActiveRecord::Base).included_modules

# Grab the model class
model = description.split('::').inject(Object){|klass,const| klass.const_get(const) }

# Get the extra modules included by the model
model_included_modules = model.included_modules
extra_modules = (model_included_modules - basic_included_modules).map(&:to_s)

# As long as we have any extra module matching the regexp, we can conclude that
# :acts_as_authentic has been declared for the model
extra_modules.any?{|mod| mod =~ /Authlogic::ActsAsAuthentic::/ }.should be_true
end

end

end
end

The usage in the spec file is:
1
2
3
4
5
describe User do
include RailsBestPractices::Macros
should_act_as_authentic
# (blah blah)
end

Of course, i can probably remove the include statement altogether & do the auto-including elsewhere, but taking this route, other developers may throw WTF-is-should_act_as_authentic error ~> BAD !!

#2. Macro for project-specific declarative
1
2
3
4
class Post < ActiveRecord::Base
include Markdownable
# (blah blah)
end

I wanna make sure the support from the home-baked Markdownable is pulled in. Since it is home-baked, just making sure the module is mixed in is not good enough, i need to ensure the functionality is there as well. Thus (nested within the above mentioned RailsBestPractices::Macros::ClassMethods module):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def should_be_markdownable

# Determine which factory to call
factory_id = description.split('::').inject(Object){|klass, const| klass.const_get(const) }.
to_s.tableize.singularize.to_sym

# Generate an example group
describe "being markdownable" do

it "should generate simple markdown html" do
raw = "subject\n=======\ntitle\n-----"
formatted = "<h1>subject</h1>\n\n<h2>title</h2>\n"
Factory(factory_id, :body => raw).formatted_html.should == formatted
end

it "should generate markdown html with <pre><code>" do
raw = "subject\n=======\ntitle\n-----\n def test\n puts 'test'\n end"
formatted = "<h1>subject</h1>\n\n<h2>title</h2>\n\n<pre><code>def test\n puts 'test'\nend\n</code></pre>\n"
Factory(factory_id, :body => raw).formatted_html.should == formatted
end

end
end

And the usage:
1
2
3
4
5
describe Post do
include RailsBestPractices::Macros
should_be_markdownable
# (blah blah)
end

#3. Macro for any other vanilla functionality
1
2
3
4
5
class Implementation < ActiveRecord::Base
def belongs_to?(user)
user && user_id == user.id
end
end

The macro definition:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def should_have_user_ownership
factory_id = description.split('::').inject(Object){|klass,const| klass.const_get(const) }.
to_s.tableize.singularize.to_sym

describe 'having user ownership' do

it 'should belong to someone if he is the owner of it' do
someone = Factory(:user)
Factory(factory_id, :user => someone).belongs_to?(someone).should be_true
end

it 'should not belong to someone if he is not the owner of it' do
someone = Factory(:user)
Factory(factory_id).belongs_to?(someone).should be_false
end

end
end

Finally, the usage:
1
2
3
4
describe Implementation do
include RailsBestPractices::Macros
should_have_user_ownership
end

Of course, it doesn't make sense to define macro for every functionality available. The general thumb of rule is that when similar code appears more than once, u can consider defining a macro for it. However, if similar-code is to appear more than once, u will probably start by extracting the code & placing it inside a module (eg. Markdownable), so this probably falls under #2. Macro for project-specific declarative.

Last but not least, the above macro definition can probably benefit from some refactoring, but i guess i'll leave this exercise to u :]

Wednesday, July 21, 2010

Relatively unknown Object#instance_exec

Do u happen to know Object#instance_eval's brother, Object#instance_exec ?? Here's a uninteresting way of coding wo Object#instance_exec:
1
2
3
4
5
6
7
8
9
10
11
12
Someone = Struct.new(:name, :password)

greet = lambda do |someone|
puts "Hey %s, no worries, i won't tell anyone ur password is '%s' !!" % [
someone.name, someone.password
]
end

greet[Someone.new('Peter', 'aabbcc')]
# >> Hey Peter, no worries, i won't tell anyone ur password is 'aabbcc' !!
greet[Someone.new('Jane', 'bbccdd')]
# >> Hey Jane, no worries, i won't tell anyone ur password is 'bbccdd' !!

And here's a more interesting way to do it, w Object#instance_exec:
1
2
3
4
5
6
7
8
9
10
11
12
Someone = Struct.new(:name, :password)

greet = lambda do
puts "Hey %s, no worries, i won't tell anyone ur password is '%s' !!" % [
name, password
]
end

Someone.new('Peter', 'aabbcc').instance_exec(&greet)
# >> Hey Peter, no worries, i won't tell anyone ur password is 'aabbcc' !!
Someone.new('Jane', 'bbccdd').instance_exec(&greet)
# >> Hey Jane, no worries, i won't tell anyone ur password is 'bbccdd' !!

Yet another way to do it can be:
1
2
3
4
5
6
7
8
9
10
Someone = Struct.new(:name, :password)
greet = lambda{|msg| puts msg % [name, password] }

Someone.new('Peter', 'aabbcc').
instance_exec("Hey %s, no worries, i won't tell anyone ur password is '%s' !!", &greet)
# >> Hey Peter, no worries, i won't tell anyone ur password is 'aabbcc' !!

Someone.new('Jane', 'bbccdd').
instance_exec("Hey %s, i'm glad that u entrust me with ur password '%s' !!", &greet)
# >> Hey Jane, i'm glad that u entrust me with ur password 'bbccdd' !!

Enjoy !!

Stubbing only the nth instance's method, should or shouldn't ?

A few days back, cross-stub version 0.2.0 has been released, with this release, cross process instance method stubbing is now possible. While doing review of zan's work, we've discussed the possibility of having more control on which exact instance the stub should be applied to, as illustrated below:
1
2
Time.xstub(:day, :instance => 1)    # applies to ONLY 1st Time instance
Time.xstub(:day, :instance => 2..3) # applies to ONLY 2nd ~ 3rd Time instances

Initially, i was quite happy to have brought up this. But after some thinking, i'm convinced that this a LOUSY idea, as it requires the user to have intimate knowledge of how many times a class's instance have been created, which can be tedious (if not impossible) if the instance method is provided by ruby core/std libs, or popular gems. It also results in extremely brittle tests, as nth can easily beconme xth, or zth ...

I think the issue is very fundamental, it goes down to how the code is written. Given the following example:
1
2
3
4
5
6
7
8
9
10
11
12
13
  class Papa
def free_today?
# Any papa is free on weekend but not weekday
!Time.now.strftime('%w').between?(0,5)
end
end

class Mama
def free_today?
# Any mama is free on weekday but not weekend
Time.now.strftime('%w').between?(0,5)
end
end

If i were to apply stubbing for Time#strftime, i would affect both Papa#free_today? & Mama#free_today?. Taking one step back, if we to affect only Papa#free_today?, we need to consider the context where the Time#strftime stub is-to-be applied, & do the following revision:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Papa

def free_today?
!today_dow.between?(0,5)
end

def today_dow
Time.now.strftime('%w')
end

end

class Mama

def free_today?
today_dow.between?(0,5)
end

def today_dow
Time.now.strftime('%w')
end

end

Therefore, by stubbing Papa#today_dow, we won't affect Mama#free_today?. Moreover, taking this approach gives us the chance to do some cleaning up:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Parent
def today_dow
Time.now.strftime('%w')
end
end

class Papa < Parent
def free_today?
!today_dow.between?(0,5)
end
end

class Mama < Parent
def free_today?
today_dow.between?(0,5)
end
end

Imagine if we go the other approach of doing nth instance's method stubbing, though feasible, the test will be extremely brittle (nightmarish maintenance), as nth can easily be changed to xth, or zth.

CONCLUSION: No, we don't need better control over nth instance's method stubbing, cross-stub's instance method stubbing is going to remain as it is. If u need it, drop me a mail with an example to justify the need :]

Sunday, July 18, 2010

Tidying up specs suite with otaku

In the specs suite of cross-stub, i've built a custom echo server using this approach to support testing of stubbing in another process. Nothing wrong with it, except that it is not so fun & clean. Anyway, over the weekend, i've extracted out the echo server code, and put it inside a new & fun project otaku.

Here's my tidied up specs (which serve as a good example usage of otaku):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
shared 'has other process setup' do

behaves_like 'has standard setup'

before do
# Don't start the service if it has already been started.
$service_started ||= (
Otaku.start do |data|

# Pull in all the helpers, __FILE__ magically converts to path of this file,
# even after otaku's internal marshalling/unmarshalling.
require File.join(File.dirname(__FILE__), '..', 'includes')

# Some processing ... using helpers & class definitions pulled in by the above
# require statement.
store_type, method_call_args = data.match(/^(.*?)\/(.*)$/)[1..2]
CrossStub.refresh(cache_store($prev_store_type)) if $prev_store_type
CrossStub.refresh(cache_store($prev_store_type = store_type))

# Actually capturing of error is not necessary, cos Otaku captures any error &
# wrap it up in Otaku::DataProcessError.
do_local_method_call(method_call_args) rescue $!.message
end

true
)
end

end

at_exit do
# Stops otaku if it has been started, only this process is abt to exit.
$service_started && Otaku.stop
end

Building a simple server/client with eventmachine 2

Following previous entry, i've come up with a drop dead simple service framework based on eventmachine, just a fun project actually, as u can see from its name "OTAKU". Since code speaks a thousand words, especially for someone like me, let's jump straight into some coding:
1
2
3
4
5
6
require 'otaku'

# Starting to otaku service
Otaku.start do |data|
result = '~ %s ~' % data
end

1
2
3
4
require 'otaku'

# client sending a process request to otaku service
Otaku.process('hello') # >> '~ hello ~'

Of course, life is never as simple as the above, since we have Otaku.start accepts a proc, most people tend to code in-a-taken-for-granted-way taking advantage of contextual references:
1
2
3
4
5
6
mark = '*'
Otaku.start do |data|
'%s %s %s' % [mark, data, mark]
end

Otaku.process('hello') # #<NameError: undefined local variable or method `mark' for ...

Now now, really unexpected rite ? The reason is that otaku converts the proc passed to Otaku.start, convert it to plain ruby code, & eval in the server process, thus, naturally, any contextual references are lost. As a workaround:
1
2
3
4
5
Otaku.start(:mark => '*') do |data|
'%s %s %s' % [mark, data, mark]
end

Otaku.process('hello') # >> '* hello *'

Well, i must admit this workaround is abit not-so-comfortable ... anyway, i'm still thinking (hard) on how the contextual references can be extracted under the hood, without having user to go through the trouble of declaring the context hash explicitely. Anyway, this is what otaku has to offer for now :]

Have a look at this slightly more complicated usage of otaku.

Thursday, July 15, 2010

Building a simple server/client with eventmachine

In writing cross-stub, i need to write specs to ensure cross process stubbing indeed work as expected. This is achieved by building a simple server/client using eventmachine, here's how echo_server.rb looks like:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
require 'rubygems'
require 'eventmachine'
require 'logger'
require 'base64'

module EchoServer

ADDRESS = '127.0.0.1'
PORT = 10999
LOG_FILE = '/tmp/echo_server.log'
INIT_WAIT_TIME = 2 # may need to increase this depending on how slow is ur machine

class << self

def log(*msg)
(@logger ||= Logger.new(LOG_FILE)) << [msg, ""].flatten.join("\n")
end

def cleanup
@logger.close
end

def start(other_process=false)
unless other_process
print 'Starting echo service ... '
@process = IO.popen("ruby #{__FILE__}",'r')
sleep INIT_WAIT_TIME
puts 'done (pid#%s)' % @process.pid
else
log 'Echo service (pid#%s) listening at %s:%s' % [Process.pid, ADDRESS, PORT]
EventMachine::run { EventMachine::start_server(ADDRESS, PORT, EM) }
end
end

def stop
Process.kill('SIGHUP', @process.pid) if @process
end

end

private

module EM

def receive_data(data)
log 'Received client data: %s' % data.inspect
result = process_data(data)
log 'Processed to yield result: %s' % result.inspect
send_data(Base64.encode64(Marshal.dump(result)))
end

def process_data(data)
# do some meaningful processing to yield result
result = '~ processed %s ~ ' % data
end

def log(*msg)
EchoServer.log(*msg)
end

end

end

if $0 == __FILE__
begin
EchoServer.start(true)
rescue
EchoServer.log "#{$!.inspect}\n"
ensure
EchoServer.cleanup
end
end

And echo_client.rb:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# Keeping things DRY, avoid repeated typing of requiring statements &
# server specific info (eg. address & port)
require File.join(File.dirname(__FILE__), 'echo_server')

module EchoClient

ADDRESS = EchoServer::ADDRESS
PORT = EchoServer::PORT

class << self
def get(data)
EventMachine::run do
EventMachine::connect(ADDRESS, PORT, EM).execute(data) do |data|
@result = Marshal.load(Base64.decode64(data))
end
end
@result
end
end

private

module EM

def receive_data(data)
@callback.call(data)
EventMachine::stop_event_loop # ends loop & resumes program flow
end

def execute(method, &callback)
@callback = callback
send_data(method)
end

end

end

And finally the example usage:
1
2
3
4
5
6
7
8
9
10
require File.join(File.dirname(__FILE__), 'echo_server')
require File.join(File.dirname(__FILE__), 'echo_client')

EchoServer.start

10.times do |i|
puts EchoClient.get(i)
end

EchoServer.stop

Personally, i prefer placing the server & client code inside a single file echo_service.rb, since the client code is pretty coupled with the server code. One gotcha i've encountered while working with this server/client thingy is that error in the server hangs the client, that's why having the server log file is really useful in debugging.

Marshal/Unmarshal problem with Jruby

While working on cross-stub today, ran into a marshal/unmarshal problem with jruby, caused by binary string encoding issue. Anyway, let's start by taking a look at some code:
1
2
3
4
5
6
time1 = Time.now
time2 = Marshal.load(
%|#{Marshal.dump(time1).gsub('|','\|')}|
)

puts time1 == time2

Here's what i got when running the above in different rubies:

#1. The expected output of Ruby 1.8.7 & Ruby 1.9.1 & Ree 1.8.7
# >> true


#2. The unexpected output of Jruby-1.5.1
# >> (eval):1:in `_load': marshaled time format differ (TypeError)

Did quite abit of research, either my googling skill sucks, or nobody has the same problem as me ... yet eventually found something at stackoverflow, which lights up the bulb, & here's the amended code that works for all the above-mentioned rubies:
1
2
3
4
5
6
7
8
9
require 'base64'

time1 = Time.now
time2 = Marshal.load(
Base64.decode64(
%|#{Base64.encode64(Marshal.dump(time1)).gsub('|','\|')}|
))

puts time1 == time2

Wednesday, July 14, 2010

Minimalist ... even more minimal than BasicObject

In cross-stub, it is possible to declare stubs using a proc:
1
2
3
4
5
  Someone.xstub do
def say(something)
'saying "%s"' % something
end
end

Implementation wise, i need a way to find out the methods delared within the proc in order to do further processing. The most straight-forward way is to have a bare minimum object, after instance_eval of the proc, do a diff of the original set of instance methods & the set of methods for this manipulated object. The following illustrates the concept:
1
2
(minimalist = Minimalist.new).instance_eval(&block)
minimalist.methods - Minimalist.instance_methods

Well, i've in fact considered using BasicObject, but then, it doesn't appear to be as basic as i hope it should it. Thus i decided to handroll my own Minimalist solution:
1
2
3
4
5
class Minimalist
alias_method :__instance_eval__, :instance_eval
alias_method :__methods__, :methods
instance_methods.each{|meth| undef_method(meth) if meth.to_s !~ /^__.*?__$/ }
end

As u can see (in order to prevent any methods clash with user-defined-to-be-stubbed-methods) what i've done is just:

#1. renaming instance_eval & methods to the more cryptic __instance_eval__ & __methods__, and
#2. undefining all methods, except those with prepending & appending __

It works well in ruby-1.8.7, but then, running the above in ruby-1.9.1 displays the following warning:

warning: undefining `object_id' may cause serious problem

With the solution suggested in this discussion, Minimalist is revised to:
1
2
3
4
5
6
7
class Minimalist
alias_method :__instance_eval__, :instance_eval
alias_method :__methods__, :methods
$VERBOSE = nil
instance_methods.each{|meth| undef_method(meth) if meth.to_s !~ /^__.*?__$/ }
$VERBOSE = true
end

Now the warning doesn't show. Yet in ruby-1.8.7, i got plenty of eval warnings:

(eval):1: warning: discarding old say
(eval):1: warning: discarding old say
(eval):1: warning: method redefined; discarding old bang

Hmmm ... undaunted, i got this final version of Minimalist:
1
2
3
4
5
6
7
class Minimalist
alias_method :__instance_eval__, :instance_eval
alias_method :__methods__, :methods
orig_verbosity, $VERBOSE = $VERBOSE, nil
instance_methods.each{|meth| undef_method(meth) if meth.to_s !~ /^__.*?__$/ }
$VERBOSE = orig_verbosity
end

Yet for jruby-1.5.1, it yields:

warning: `instance_eval' should not be aliased

The final final final (i promise) Minimalist becomes:
1
2
3
4
5
class Minimalist
orig_verbosity, $VERBOSE = $VERBOSE, nil
# (method aliasing & removal stays here)
$VERBOSE = orig_verbosity
end

Tuesday, July 6, 2010

Binding of or/and & ||/&&

Got bitten today by:
1
2
3
4
5
def call_1 ; false ; end
def call_2 ; true ; end

x = call_1 or call_2
# x => false

Because of binding issue of or, x is assigned to return of call_1 first, prior separated calling of call_2. Since what i actually want is to assign x to whichever valid (non nil/false) value of call_1 or call_2, i should use ||, which as a stronger binding, and code as:
1
2
x = call_1 || call_2
# x => true

The same applies for && & and.

Thursday, December 10, 2009

Adding Webrat Matchers to Culerity

If u are using culerity, and somehow u missed the webrat matchers, eg. has_xpath(), here's what u can do:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
require 'webrat/core/xml'
require 'webrat/core/matchers'

module WebratLike

include Webrat::Matchers

def response
html = $browser.html
def html.body ; to_s ; end
html
end

end

World(WebratLike)
end
end

Enjoys !!

Sunday, November 29, 2009

Fetching plain ruby code on the fly

Last weekend, zan showed me howto use parsetree & ruby2ruby to dynamically extract a method definition in plain ruby code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
%w{rubygems ruby2ruby parse_tree}.each {|lib| require lib }

class Hello

def self.hello
puts "class says hello"
end

def hello
puts "instance says hello"
end

end

extract_code = lambda do |klass, method|
sexp = ParseTree.translate(klass, method)
Ruby2Ruby.new.process(Unifier.new.process(sexp))
end

instance_method_code = extract_code[Hello, :hello]
puts instance_method_code
# >> def hello ; puts("instance says hello") ; end

To get the class method:
1
2
3
4
metaclass = (class << Hello ; self ; end)
class_method_code = extract_code[metaclass, :hello]
puts class_method_code
# >> def hello ; puts("class says hello") ; end

It is even possible to extract the entire class definitions:
1
2
3
4
5
puts extract_code[World, nil]
# >> class World < Object
# >> def hello ; puts("instance says hello") ; end
# >> def self.hello ; puts("class says hello") ; end
# >> end

There are probably tonnes of code stuff you can do with the above capability. One immediate use case i can think of is appending new instance/class methods to another class:
1
2
3
4
5
6
class World ; end
World.class_eval instance_method_code
World.instance_eval class_method_code

World.hello # yields: class says hello
World.new.hello # yields: instance says hello

Another is that we can store the method definition somewhere (db, file, ...), redefine, distort, assault, murder, arson the existing class, and later just rollback the damages:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
cache = {'Hello.hello' => extract_code[Hello, :hello]}
File.open('/tmp/original_methods', 'w') {|f| Marshal.dump(cache, f) }

class Hello
def hello ; puts "instance is murdered" ; end
end

puts Hello.new.hello
# >> instance is murdered

# Do lots of other bad stuff, and to undo the damages:

cache = File.open('/tmp/original_methods', 'r') {|f| Marshal.load(f) }
Hello.class_eval = cache['Hello.hello']

puts Hello.new.hello
# >> instance says hello

Thursday, November 26, 2009

Ways to create symbol on the fly

To convet a string to a symbol on the fly:

# Method 1:
1
2
3
type = "elective"
course = "#{type}_course".to_sym
# >> :elective_course

# Method 2:
1
2
3
type = "core"
course = :"#{type}_course"
# >> :core_course

Wednesday, November 25, 2009

Dynamically defining class method

There is this concept of metaclass in ruby. If we wanna dynamically define a class method, we need to play with metaclass:
1
2
3
4
5
6
7
8
9
10
11
12
class Human
def self.say_hello
puts %\class says 'hello'\
end
end

message = 'hello world'
meta_klass = (class << Human ; self ; end)
meta_klass.send(:define_method, :say_hello) { puts %\class says '#{message}'\ }

Human.say_hello
# >> class says 'hello world'

Labels