12.07.07
Posted in Ruby at 1:07 pm by Robert Horvick
As I become more familiar with the Ruby language I have also become more familiar with the global Ruby community (though it will be quite some time before I am familiar to them).
As in all language spaces there are the founders, leaders, thinkers, personalities, corporate players, and random people you’d drink with (if the opportunity presented itself).

What’s interesting about this community, though, is the theme of happiness that everyone keeps talking about.
As in other communities people discuss language features, benefits, failures, frameworks, productivity, metrics, performance, blah blah blah. But this whole notion of happiness, as a language feature, is new to me.
I worked on a commercial compiler for several years early in my career and not once did the word “happiness” come up in design discussions or feature lists. “Tolerable”. “Correctness”. “Performant” (one of my favorite made up words). Absolutely.
But not happiness.
I’m trying to let it soak in slowly. People seem to be happy for basically the same reasons. It boils down to the “feel” of the language. The expressiveness of it. The ease at which things happen. Least surprise. Agile principles. BDD/TDD. RSpec. Lots of good stuff.
And, of course, Rails (and all the MVC, ORM, pluggable goodness it brings to the table).
For me, though, it’s none of those things. Those same things exist in other languages (and will in future languages).
Those things are brick construction, crown modeling and custom paint. Solid. Attractive. Welcoming. Stylish. Fun. But there are other well-made and attractive homes. In the future there will be new well made attractive homes.
Why this one? Why Ruby?
Just like when we picked the neighborhood for our home - it’s the local community. The Raleigh-area Ruby Brigade (Raleigh.rb). Sitting in on the meetings and learning from others. Hearing their stories about past, present and future projects. Listening to their excitement around Ruby and Rails. Learning from them and talking about development topics over laptops and burritos.
Associating with people who are smart, passionate, excited, and who get things done is infectious.
Even just for a few hours a month.
It gets me going. Pushes me to work on my own projects. Revitalizes my spirit. Inspires me to try out new things.

Seeing talented developers with a flare for design pushes me to improve my design skills. I’ve begun reading about graphic design, typography, print layouts, usability and photo processing. I’ve started to draw again. I’m sleeping less (in a good way), thinking more, and generally more excited about my day-to-day work (C#, not Ruby). I’m reconnecting with that person I used to be before I got trapped in the clutches of a monolithic corporate machine. He is much cooler than I am. At least he had better taste in socks.
None of this is really about Ruby as a language, though. It could just as well be Python or a Linux fetish. I’m sure there are some great local groups for those technologies.
But I’m not in those groups. I’m in Raleigh.rb. Maybe I’ll check them out some other time. Maybe not. I’m still having fun here.
So go now. Seek out a local Ruby Brigade in your community. If you can’t find one then start your own.
Sit in the back. Don’t say a word. Or sit up front and chat the place up. Doesn’t matter. Just find one and go. If you’re in the Raleigh area come by to the local meetup. I’ve found it to be a friendly, open group who enjoy seeing new faces.
Make it a New Year’s resolution.
You’ll be glad you did.
I promise.
Permalink
11.29.07
Posted in Ruby, rails at 5:00 am by Robert Horvick
To give users a better view into some data I want to render local points of interest with current deals onto a Google map. In the marker popup I’d like the user to be able to drill down further into the details. To do this I want a hyperlink to the deal details.
The link_to I want is:
link_to "Details", { :controller => "deal", :action => "details", :id => deal.id }

The problem is that the rendered <a> should go into a blob of javascript such as:
GEvent.addListener( marker,"click", function() {
var myHtml = "<b><%= h deal.Restaurant.name %></b><br/><%= h deal.description %></br><%= link_to "Details", { :controller => "deal", :action => "details", :id => deal.id } %>";
map.openInfoWindowHtml(marker.getLatLng(), myHtml);
}
);
That fails because the string literal has embedded double quotes.
Since ‘h’ (alias for html_escape) exists I figured there had to be a javascript version as well - and action view did not disappoint.
The updated code is:
GEvent.addListener( marker,"click", function() {
var myHtml = "<b><%= escape_javascript h(deal.Restaurant.name) %></b><br/><%= escape_javascript h(deal.description) %></br><%= escape_javascript link_to("Details", { :controller => "deal", :action => "details", :id => deal.id }) %>";
map.openInfoWindowHtml(marker.getLatLng(), myHtml);
}
);
The javascript now renders correctly and the link to the details page functions as expected.
I’m still shooting in the dark - but I think I’m facing the target.
Permalink
11.28.07
Posted in Ruby, rails, rspec, testing at 6:00 am by Robert Horvick
Since bringing a copy of my current project down from heroku to test some features I decided to give RSpec a try at the same time.
My gut feeling was to run “gem install rspec”. So, for the record, that is NOT the way to properly install rspec on a rails site.
To use rspec on a rails site you need to install it as a plugin.
The documentation page on installing RSpec indicates that I should do this be running the following commands from my ruby shell:
ruby script/plugin install svn://rubyforge.org/var/svn/rspec/tags/CURRENT/rspecruby script/plugin install svn://rubyforge.org/var/svn/rspec/tags/CURRENT/rspec_on_rails
When I did this nothing happened. No output whatsoever.
I tried running the next command on the install guide (output provided):
>ruby script/generate rspec
Couldn't find 'rspec' generator
I figured the problem was not having svn installed (let me take a moment here to say that the plugin script could do a better job of indicating this - silent failure smells a lot like success).
I installed downloaded the win32 client binaries from the subversion site http://subversion.tigris.org/downloads/1.4.5-win32/apache-2.2/svn-win32-1.4.5.zip and extracted them to c:\svn (so c:\svn\bin now contains svn.exe).
In my ruby command shell I added c:\svn\bin to the path (set PATH=%PATH%;c:\svn\bin) and now re-running the plugin installation succeeded (thousands of lines of status scroll by).
Next I ran the following (with output):
C:\InstantRails\rails_apps\kidseatfree>ruby script\generate rspec
exists spec
create spec/spec_helper.rb
create spec/spec.opts
create previous_failures.txt
create script/spec_server
create script/spec
Finally I ran “rake spec” - which showed I had a missing gem dependency:
C:\InstantRails\rails_apps\kidseatfree>rake spec
(in C:/InstantRails/rails_apps/kidseatfree)
C:/InstantRails/rails_apps/kidseatfree/vendor/plugins/rspec/lib/spec/runner/formatter/base_text_formatter.rb:37:in `colour=': You must gem install win32console to use colour on Windows (RuntimeError)
So I ran “gem install win32console” and now rake spec gave the following (I already had an rspec test written so there was something to do):
Errno::ENOENT in 'Deal with fixtures loaded should have one record'
No such file or directory - C:/InstantRails/rails_apps/kidseatfree/config/../spec/fixtures/deal
So I copied my fixtures from test\fixtures to spec\fixtures and re-ran:
C:\InstantRails\rails_apps\kidseatfree>rake spec
(in C:/InstantRails/rails_apps/kidseatfree)
..Finished in 0.166 seconds
2 examples, 0 failures
Permalink
11.26.07
Posted in Programming, Ruby, ajax, heroku, rails at 4:55 pm by Robert Horvick
Update: As I expected the guys are heroku turned around a fix very quickly. I tested autocompletion tonight and it worked perfect. heroku + script.aculo.us = working like a champ :)
They say that constructive criticism (e.g. complaints) should occur in a sandwich of positive thoughts. Generally I think that’s a bunch of PC granola-farming nonsense. People need to hear what people need to hear. If I suck - tell me. If I’m lucky you’ll tell me why. If I’m really lucky you may offer advice on how to improve.
But knowing that something sucks is the baseline.
But I’m going to break my rule and go with the PC warm-fuzzy approach.
Positive: Heroku kicks ass
Rails site online fast, syntax highlighting editor, backup/restore, nginx, postgres … love it. I’ve been able to make a lot of progress in this environment (and being able to work on the site from multiple computers is very nice).
Negative: Heroku injects some code into every response
This breaks ajax behaviors by altering partials (and includes prototype.js which breaks script.aculo.us) … in short ajaxy rails is broken.
When I make an ajax request I expect to get back something like:
<ul class="restaurants">
<li class="restaurant"> <div class="name">rest name</div>
</li>
<li class="restaurant">
<div class="name">O'Charley's</div>
</li>
<li class="restaurant">
<div class="name">Sunday Deal</div>
</li>
<li class="restaurant">
<div class="name">Monday Deal</div>
</li>
<li class="restaurant">
<div class="name">Sunday Cheap</div>
</li>
</ul>
But what I actually get back is:
<!-- heroku toolbar -->
<script src="http://heroku.com/javascripts/prototype.js” type=”text/javascript”></script>
<script src=”http://heroku.com/javascripts/effects.js” type=”text/javascript”></script>
<script src=”http://heroku.com/toolbar/heroku_toolbar.js” type=”text/javascript”></script>
<link href=”http://heroku.com/toolbar/heroku_toolbar.css” media=”screen” rel=”Stylesheet” type=”text/css” />
<script type=”text/javascript”>HerokuToolbar.html = ‘<div id=”heroku_toolbar”><a href=”http://heroku.com” id=”heroku_logo”></a><a href=”http://edit.kidseatfree.heroku.com/?uri=%2Fdeal%2Fauto_complete_for_restaurant_name” id=”heroku_back_button”></a><a href=”javascript:HerokuToolbar.toggle()” mce_href=”javascript:HerokuToolbar.toggle()” id=”heroku_inspect_button”></a><img id=”heroku_spinner” src=”http://heroku.com/toolbar/images/spinner.gif” style=”display: none”><span id=”heroku_login_info”><a href=”http://heroku.com/myapps”>robert.horvick@gmail.com</a> | <a href=”http://heroku.com/logout”>logout</a></span></div>’</script>
<span class=”heroku_marker heroku_start” style=”display: none”>/mnt/home/userapps/347/app/views/deal/_restaurants.rhtml</span>
<ul class=”restaurants”>
<li class=”restaurant”> <div class=”name”>rest name</div>
</li>
<li class=”restaurant”>
<div class=”name”>O’Charley’s</div>
</li>
<li class=”restaurant”>
<div class=”name”>Sunday Deal</div>
</li>
<li class=”restaurant”>
<div class=”name”>Monday Deal</div>
</li>
<li class=”restaurant”>
<div class=”name”>Sunday Cheap</div>
</li>
</ul>
<span class=”heroku_marker heroku_finish” style=”display: none”></span>
Ah crap. Now my autocomplete doesn’t render … oh but it gets worse.
Reincluding prototype.js causes the scriptaculous extending of Ajax.Autocompleter to be lost and now autocomplete events don’t fire (in fact FireBug shows an error because Ajax.Autocompleter is not a constructor).
Bug reported.
Positive: The folks at heroku kick ass
I have reported quite a few issues - some bugs, some feature ideas, some random rants about usability or business models. But in every case these guys have turned around fixes or offered workarounds in a matter of hours.
The issue I just described - I’m confident that they will be able to work past it quickly or provide some sort of workaround for the specific case of partials.
So there you go.
A feedback sandwich.
Now I’m hungry.
Permalink
11.25.07
Posted in MySQL, Programming, Ruby, rails at 6:10 pm by Robert Horvick
I want to create a simple site that allows users to add event, restaurant and location details through an ajax-ish interface. Ultimately I have a design in mind but to get there I need to be able to submit details of multiple models through a single form (there are about 10 fields over 4 models that will need to be defined).
I wanted to use the action view “form_for”, a single submit and have the submission automatically map the fields to their proper object so that my controller method could look like this (sans error handling):
def create
if request.post?
@deal = Deal.new(params[:deal])
@deal.Restaurant = Restaurant.new(params[:restaurant])
@deal.Location = Location.new(params[:location])
@deal.save
end
end
Long story short - what you need to do is use the “fields_for” call within the form to get the model information. The form in the view looks like:
<% form_for :deal, :url => { :action => :create } do |form| %>
<% fields_for :restaurant do |r| %>
Restaurant: <%= r.text_field :name %><br/>
<% end %>
<% fields_for :location do |l| %>
Address 1: <%= l.text_field :address1 %><br/>
Address 2: <%= l.text_field :address2 %><br/>
City: <%= l.text_field :city %><br/>
State: <%= l.text_field :state %><br/>
Zip: <%= l.text_field :zip %><br/>
<% end %>
Details: <%= form.text_area :description, :rows => 3 %>
<%= submit_tag %>
<% end %>
In this example three models are used - Deal, Restaurant and Location.
The form is based on Deal (since I want the submit to go to Deal::create and I defined two fields_for blocks - one for Restaurant and Location.
The params.inspect output of the form data is:
Parameters: {”restaurant”=>{”name”=>”rest name”}, “deal”=>{”description”=>”Kids can eat whatever they want in under 3 minutes.”}, “commit”=>”Save changes”, “location”=>{”city”=>”some place”, “address1″=>”address one”, “zip”=>”12345″, “address2″=>”", “state”=>”NC”}}
Notice that restaurant, deal and location are all their own hash which can be passed to the new method on the respective models.
Worked like a champ.
Details on the schema is:
create_table :locations do |t|
t.column :address1, :string, :limit => 60
t.column :address2, :string, :limit => 60
t.column :city, :string, :limit => 40
t.column :state, :string, :limit => 2
t.column :zip, :string, :limit => 10
t.column :phone, :string, :limit => 16
t.column :lng, :string, :limit => 30
t.column :lat, :string, :limit => 30
t.column :restaurant_id, :int
end
create_table :restaurants do |t|
t.column :name, :string, :limit => 60
end
create_table :deals do |t|
t.column :restaurant_id, :int
t.column :location_id, :int
t.column :description, :text
end
And the models relationships:
class Deal < ActiveRecord::Base
belongs_to :Restaurant
belongs_to :Location
...
end
class Location < ActiveRecord::Base
belongs_to :Restaurant
end
class Restaurant < ActiveRecord::Base
has_many :Location
has_many :Deal
...
end
Permalink
11.21.07
Posted in Programming, Ruby, rails at 7:30 pm by Robert Horvick
Using heroku I’m working on a small rails app that needs to integrate with google maps.
The Plan
I want to do is allow a user to provide a location which I will store and later be able to render on a google map.
Now, to use Google Maps to store location data you want to be using geocodes (i.e. longitude/latitude values). There are a few reasons for this:
- Ultimately adding a marker requires a geocode.
- Google limits how many address-to-geocode conversions a site can perform (I’ve seen daily and weekly limits - they were 15,000 and 50,000 respectively [which doesn't add up - but whatever]).
- Converting from address to geocode takes a second or longer. Why make the viewer wait when the information only needs to be gathered once?
So the plan was to do the following:
- Accept the data in a standard address form.
- Contact the google web service for geocode creation
- Cache the geocode with the location record in SQL
- Subsequent requests would use the cached record
Reality Bites
The problem is that heroku does not allow outgoing connections so I can’t perform #2. So I need to get the information from the caller without actually making them enter it. What I came up with was:
- Get the data from the user
- Perform the geocode lookup in javascript on form submit
- Note the geocodes on a pair of hidden form fields
- Submit using javascript
Get the data from the user
Let’s get right to it. This is the form code in the rails view (index.rhtml):
<%= form_tag( {:controller => “location”, :action => “create”},
{’id’ => ‘frmAddress’, ‘method’ => ‘post’, ‘onSubmit’ => ’showAddress(this); return false;’} ) %>
<p>
<%= text_field_tag( :address ) %>
<%= hidden_field_tag( :lat ) %>
<%= hidden_field_tag( :lng ) %>
<%= submit_tag(”Go”) %>
</p>
<div id=”map_canvas” style=”width: 500px; height: 300px”></div>
<%= end_form_tag %>
Time for a little breakdown:
<%= form_tag( {:controller => “location”, :action => “create”},
{’id’ => ‘frmAddress’, ‘method’ => ‘post’, ‘onSubmit’ => ’showAddress(this); return false;’} ) %>
We are submitting the form to the location controller’s “create” action. We will submit using the post method. The ‘id’ isn’t needed in this example - ignore it. When the submit button is clicked we will call the showAddress javascript function and pass the form as the parameter. So what’s with return false?
OMG - this is so important. I can NOT stress this enough.
When submitting a form via javascript you must (MUST) have this return false. If you don’t the form will submit twice - once via the javascript submit and once via the normal form post.
Say it with me - if javascript is submitting the form I will return false. I will return false!!!
By the way - Agile Web Development With Rails had this information on 537 (form_remote_tag and remote_form_for documentation).
<%= hidden_field_tag( :lat ) %>
<%= hidden_field_tag( :lng ) %>
These are the hidden fields for the longitude and latitude.
Everything else is plain-jane form stuff.
Lookup, record, submit
function showAddress(frm) {
if (geocoder) {
geocoder.getLatLng(
frm.address.value,
function(point) {
if (!point) {
alert(address + ” not found”);
} else {
frm.lat.value = point.lat();
frm.lng.value = point.lng();
frm.submit();
}
}
);
}
This is mostly the stock google sample code except that I am storing away the latitude and longitude in the hidden form fields and I changed the function to take the form instead of the address value.
Also I submitted the form.
Now in the controller’s create method I can access the parameters like:
def create
@lat = params[:lat]
@lng = params[:lng]
@address = params[:address]
end
And display them in the view like:
Long: <%= @lng %><br/>
Lat: <%= @lat %><br/>
Address: <%= @address %><br/>
So it’s not the server-side solution I had hoped for but it gave me a chance to try something AJAX-ish and to make use of a more complex form submission approach.
Alright … now what have I done wrong?
Permalink
11.17.07
Posted in Programming, Ruby, merb at 12:09 am by Robert Horvick
UPDATE: Installing Merb on Windows is now a lot easier! Check it out here.
This post outlines the exact steps I took to get merb working on Windows (to be specific - Vista Home Premium)
- Install InstantRails (I have no reason to believe this won’t work with the one-click installer).
- Start InstantRails and open a Ruby Console window (the steps following take place in that window)
- Execute “gem install hoe” (RubyInline depends on hoe)
- Download http://web.mit.edu/~agp/www/parsetree-win32/ParseTree-2.0.2-mswin32.gem
- Download http://web.mit.edu/~agp/www/parsetree-win32/RubyInline-3.6.4.gem
- Execute “gem install RubyInline-3.6.4.gem”
- Execute “gem install ParseTree-2.0.2.mswin32.gem”
- Execute “gem install ruby2ruby”
- Execute “gem install json” (choose json 1.1.1 (mswin32))
- Execute “gem install merb -y”
- Execute “merb myapp”
- Execute “cd myapp”
- Execute “set INLINEDIR=c:/temp” (the slash direction matters!)
- Execute “merb”
- Browse to http://localhost:4000 and …

So a big thanks to Ezra for providing the pointers I needed.
Hopefully these steps will prove useful for others.
Permalink
11.16.07
Posted in Programming, Ruby, merb at 11:56 pm by Robert Horvick
After my last merb post Ezra left a comment with some concrete suggestions to move forward with getting merb working on Windows. My next post will cover that exact topic but I wanted to create a post to captute the stack traces of the errors I hit when trying to get merb running.
The first was a dependency issue. Merb requires json but I did not have it installed. I think the merb gem should have noted this dependency but honestly I don’t understand gems enough to know for sure. The output of the merb command and call stack is:
C:\InstantRails\ruby\merb>merb
Merb started with these options:
—
:query_string_whitelist: []
:reloader: true
:environment: development
:merb_root: C:/InstantRails/ruby/merb
:exception_details: true
:cache_templates: false
:reloader_time: 0.5
:host: 0.0.0.0
:use_mutex: true
:port: “4000″
:session_id_cookie_only: true
Using pure ruby JSON lib
Using pure ruby JSON lib
C:/InstantRails/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require’: no such file to load — json/pure (LoadError)
from C:/InstantRails/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `require’
from C:/InstantRails/ruby/lib/ruby/gems/1.8/gems/merb-0.4.1/lib/merb.rb:28
from C:/InstantRails/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:32:in `gem_original_require’
from C:/InstantRails/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:32:in `require’
from C:/InstantRails/ruby/lib/ruby/gems/1.8/gems/merb-0.4.1/lib/merb/server.rb:236:in `initialize_merb’
from C:/InstantRails/ruby/lib/ruby/gems/1.8/gems/merb-0.4.1/lib/merb/server.rb:573:in `mongrel_start’
from C:/InstantRails/ruby/lib/ruby/gems/1.8/gems/merb-0.4.1/lib/merb/server.rb:509:in `run’
from C:/InstantRails/ruby/lib/ruby/gems/1.8/gems/merb-0.4.1/bin/merb:6
from C:/InstantRails/ruby/bin/merb:16:in `load’
from C:/InstantRails/ruby/bin/merb:16
I fixed this by installing json 1.1.1 (mswin32).
C:\InstantRails\ruby\merb>gem install json
Select which gem to install for your platform (i386-mswin32)
1. json 1.1.1 (mswin32)
2. json 1.1.1 (ruby)
3. json 1.1.0 (mswin32)
4. json 1.1.0 (ruby)
5. Skip this gem
6. Cancel installation
> 1
Successfully installed json-1.1.1-mswin32
Installing ri documentation for json-1.1.1-mswin32…
No definition for cState_configure
No definition for cState_configure
Installing RDoc documentation for json-1.1.1-mswin32…
No definition for cState_configure
No definition for cState_configure
With the dependencies resolved I re-ran merb but hit another error message. I’ll give you the output and call stack first and see if you see the problem:
C:\InstantRails\ruby\merb>merb
Merb started with these options:
—
:query_string_whitelist: []
:reloader: true
:environment: development
:merb_root: C:/InstantRails/ruby/merb
:exception_details: true
:cache_templates: false
:reloader_time: 0.5
:host: 0.0.0.0
:use_mutex: true
:port: “4000″
:session_id_cookie_only: true
C:/InstantRails/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require’: no such file to load — C:/InstantRails/ruby/merb/config/merb_init.rb (LoadError)
from C:/InstantRails/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `require’
from C:/InstantRails/ruby/lib/ruby/gems/1.8/gems/merb-0.4.1/lib/merb/server.rb:250:in `initialize_merb’
from C:/InstantRails/ruby/lib/ruby/gems/1.8/gems/merb-0.4.1/lib/merb/server.rb:573:in `mongrel_start’
from C:/InstantRails/ruby/lib/ruby/gems/1.8/gems/merb-0.4.1/lib/merb/server.rb:509:in `run’
from C:/InstantRails/ruby/lib/ruby/gems/1.8/gems/merb-0.4.1/bin/merb:6
from C:/InstantRails/ruby/bin/merb:16:in `load’
from C:/InstantRails/ruby/bin/merb:16
See it yet?
Require failed to find the file C:/InstantRails/ruby/merb/config/merb_init.rb. But why?
Because I’m an idiot :). I ran the merb command from the wrong directory. I needed to move to the application directory at which point I re-ran merb and …
Wait for the next post!
Permalink
11.14.07
Posted in Programming, Ruby at 8:32 pm by Robert Horvick
In my effort to understand more about ActiveRecord, and Ruby in general, I have been digging through AR line by line.
One of my first goals was to figure out how the dynamic attributes and find_* methods worked. I mean … you call a method and it’s not there and then somehow it gets created.
In the .NET world I would expect something like:
try {
object.Invoke("Method", args);
} catch(MissingMethodException) {
// Use the CodeDOM or Emit to generate some code and defer to the created object
}
Was that happening here? Turns out it’s not far off.
I started by creating a case I knew would fail:
class MissingMethod
end
mm = MissingMethod.new
mm.does_not_exist("argument")
# Exception: undefined method `does_not_exist' for #<MissingMethod:0x32171c4>
So how to capture that? Well - I figured ActiveRecord::Base needed to do that so I started there and found “method_missing”. Awesome
So I add a handler and now I’m looking like:
class MissingMethod
def method_missing(method_id, *arguments)
puts method_id
end
end
mm = MissingMethod.new
mm.does_not_exist("argument")
# does_not_exist
Sweet.
Now I want to get that whole dynamic goodness thing to happen. So I set out to create a class that would take any missing method that starts with “call_*” and extract the “*” portion, see if that method exists and call it with the original arguments if it does.
So obj.call_real_method(arg) would in turn call obj.real_method(arg).
So now I’m left with a few tasks:
- split off the real method name
- figure out if it exists
- call it
The splitting was easy to figure out:
if match = /^call_([_a-zA-Z]\w*)$/.match(method_id.to_s)
method = match.captures[0]
Figuring out if it existed took a little more research. I dug into the method_missing handler in ActiveRecord and fairly quickly ran into respond_to? which, after checking some docs, looked perfect.
if(respond_to?(method))
Finally I needed to pass along the call. I did not see an obvious invoke method so I checked out places in ActiveRecord that called respond_to? and noticed the pattern of calling __send__ shortly after. This looked promising. A few doc checks later and my sample was done.
class MissingMethod
def method_missing(method_id, *arguments)
if match = /^call_([_a-zA-Z]\w*)$/.match(method_id.to_s)
method = match.captures[0]
if(respond_to?(method))
__send__ method, arguments
else
super
end
else
super
end
end
def display(arg)
puts arg
end
end
mm = MissingMethod.new
mm.call_display(”Hello World”)
When run prints “Hello World”
As for ActiveRecord - it is doing more than that, obviously. It is not just deferring to existing methods but rather also generating them, adding them to a hash and then calling the generated method from the hash. But this is that point of diminishing interest. I can see the goal line from here so it’s time to move on to the next topic before I get bogged down in the details instead of getting my head around the big picture.
Permalink
« Previous entries · Next entries »