Using the question mark for string equations.
Roy van der Meij di 22 jun 10
In rails we have the method Rails.env.production? which simply checks if Rails.env equals “production”
I kinda liked that and I was curious how they did that.
It appears that DHH himself made a class StringInquirer which had a nifty method_missing method.
Let’s check it out! (you can find this file in gems/active_support#{version}/lib/active_support/string_inquirer.rb)
module ActiveSupport class StringInquirer < String def method_missing(method_name, *arguments) if method_name.to_s[-1,1] == "?" self == method_name.to_s[0..-2] else super end end end end
With this knowledge we can do something like this.
fancyness = ActiveSupport::StringInquirer.new("fancy") fancyness.fancy? => true fancyness.lame? => false
So what do we do when we want to make this core functionality for any stringg?
Simple! Monkey patch the class String!
class String def method_missing(method_name, *arguments) if method_name.to_s[-1,1] == "?" self == method_name.to_s[0..-2] else super end end end "fancy".fancy? => true a = "awesome" a.awesome? => true a.stupid? => false
I personally like it more to have core extensions in separate modules instead of hacking the String class directly. So here is the cleaned up version.
module CoreExtensions module StringExtensions def method_missing(method_name, *arguments) if method_name.to_s[-1,1] == "?" self == method_name.to_s[0..-2] else super end end end end String.send :include, CoreExtensions::StringExtensions "fancy".fancy? => true
So… is it fancy?
Gepost in hor | 0 reacties
Netzke
Jeroen Bulters ma 21 jun 10
While I didn’t have the time to check it out myself yet; a friend of mine recommended me to have a look at Netzke. Netzke is a gem designed for usage with Rails which will allow you to easily include ExtJS components into your app (i.e. views).
I’m personally not the biggest fan of these semi-native bindings, but basic usage looks quite simple (and promising). This one goes into the list for usage on a next weekend-side-project.
Gepost in hor | 0 reacties
Immutable Attributes in Ruby On Rails
Chiel Wester ma 21 jun 10
Sometimes you want to have some attributes on models that can be changed only on creation or only on certain conditions.
Of course there is attr_protected (to prevent mass assignment) and attr_readonly, but with these methods it’s difficult to create the conditions we actually want to apply.
For these situations you can install the immutable_attributes gem. Simple set the following in your model:
class Relation < ActiveRecord::Base attr_immutable :name end
The attribute will be readonly for all (in this case) relations.
When you want to apply the immutable function only on certain conditions, you can do the following:
class Relation < ActiveRecord::Base validates_immutable :name, :if => Proc.new{|relation| relation.is_active?} end
This function works like a validation, so you will get an validation error when you try to change the specified attribute.
Gepost in hor | 0 reacties
Smash Into Vim
Dax Huiberts ma 14 jun 10
Not so long ago PeepCode released a screencast titled ‘Smash Into Vim’. In this screencast created by Andrew Stewart (voiceover by Dan Benjamin) you will be introduced to the power of the Vim text editor. Vim was specifically build to help programmers edit text more efficiently. Because of it’s origins in the terminal it can be daunting at first, but with a little practice you will find it well worth the effort.
The things that are covered are:
- Install Vim for your platform
- Use Vim for simple editing via SSH
- Configure Vim with sensible defaults (basic and advanced configurations are included in the code download)
- Use operators and commands to manipulate text
- Work with files, windows and buffers
- Install plugins
While you might be very happy with TextMate or another editor of your choice. I believe it’s a good idea to at least try it out. It may very well become your most powerful tool in your Ruby toolbox. As usual, this screencast costs a mere $9!
PS: Part II is in post-production and will go further into advanced editing and plugins.
Gepost in hor | 1 reactie
Fixing i18n backend cache key when using memcached and Ruby 1.8.6
Paul Engel vr 11 jun 10
Implementing internationalization for Rails sites is a common thing. Most of you are likely using the i18n library developed by Sven Fuchs.
Backends and chaining them together
The default backend (I18n::Backend:: Simple) reads its translations from YAML files stored in the /config/locales directory and uses an in-memory hash to ensure efficiency. In most cases, this backend is sufficient enough when the application doesn’t require translation management by end-users. But if so, storing translations within YAML files isn’t preferred. You want to use a database for doing this.
Fortunately, i18n also provides a backend for database storage (I18n::Backend::ActiveRecord). Chaining both backends enables you to define translations within the YAML files and to override them with translations stored in the database.
I18n.backend = I18n::Backend::Chain.new(I18n::Backend::ActiveRecord.new, I18n.backend)
The usage of memcached ensures efficiency.
require "memcache" yaml = YAML.load(File.read(File.join(RAILS_ROOT, "config", "memcached.yml"))) config = yaml["defaults"].merge yaml[RAILS_ENV || "development"] mem_cache = MemCache.new config mem_cache.servers = config["servers"] I18n.cache_store = ActiveSupport::Cache.lookup_store :mem_cache_store, mem_cache
The problem
Using this setup in Ruby 1.8.6 can raise an error caused by an invalid memcached cache key. This key is generated by the protected method I18n::Backend::Cache.cache_key which doesn’t provide a clean key in Ruby 1.8.6 as it uses the Hash.hash method to create the key. The pitfall is that isn’t reliable in Ruby < 1.8.7:
{}.hash != {}.hash.
The fix
A solution is to upgrade Ruby, but doing this can bring a lot of side effects to Ruby dependent libraries on your system. We are clearly searching for some 1.8.7 goodies to use in 1.8.6. Fortunately, Marc-André Lafortune has created the gem Backports which provides us just that.
But as backports is not endorsed by ruby-core and you’re noted to use this with caution!
To fix the I18n cache key problem, just extract the hash method backport and use it in your project:
class Hash def hash h = 0 each do |key, value| h ^= key.hash ^ value.hash end h end unless {}.hash == {}.hash end
Enjoy!
Gepost in hor | 0 reacties
Rails 3 screen casts
Johan Vermeulen wo 09 jun 10
Gregg Pollack just released a couple of screencasts about all what’s new in Rails 3.
These are the topics that will be covered:
Getting Started & Action Dispatch
Active Relation & Active Model
Cross-site scripting & Unobtrusive JS
Have fun watching!
Gepost in hor | 1 reactie
$ 3.0.0.beta4
Stephan Kaag di 08 jun 10
The Rails core team is very pleased to announce Rails 3 beta 4, which they will be hammering on and tuning during RailsConf. At the end of RailsConf, they will be putting out the release candidate.
You can install the latest beta with gem install rails --pre
Gepost in hor | 0 reacties
Unroller
Jeroen Bulters ma 07 jun 10
When working with a new piece of code, being a new plugin, gem or just some code someone else wrote, and you want to familiarise yourself with the inner workings you can do a few things.
Play around with it in irb (or script/console) and try out different options, while keeping the code as a reference. Or you pull out the debugging-swiss-army-knife named Unroller (available as a gem with the same name).
Unroller is a custom tracing module designed with this kind of situations in mind and is very easy to use.
Image the following – useless – piece of Ruby code which calls the same function 4 times, followed by some other function.
require 'rubygems' require 'unroller' class Recurse def self.some_recursive_function(times, callback, depth=0) if depth == times self.send(callback) return else puts "Depth is #{depth}" some_recursive_function(times, callback, depth+1) end end def self.end_of_recursion_callback puts "End of recursion" end end Recurse.some_recursive_function(3, :end_of_recursion_callback)
Of course, this example is quite trivial, but imagine for a second we do not understand how it works.
By wrapping the method call in a Unroller block we can easily generate an easily understandable stacktrace.
So, we replace the Recurse#some_recursive_function call with the following:
Unroller::trace do Recurse.some_recursive_function(3, :end_of_recursion_callback) end
And run the file again.
This time, we are presented with a nice stack trace showing each step of the execution:
| Recurse.some_recursive_function(3, :end_of_recursion_callback) | unroll.rb:23 | \ calling Recurse::some_recursive_function Recurse::some_recursive_function (unroll.rb:6) (line): | | (times = 3; callback = :end_of_recursion_callback; depth = 0)... def self.some_recursive_function(times, callback, depth=0) -> if depth == times self.send(callback) return else puts "Depth is #{depth}" some_recursive_function(times, callback, depth+1) end end --- SNIP FOR BREVITY --- Recurse.some_recursive_function(3, :end_of_recursion_callback) Unroller::trace do Recurse.some_recursive_function(3, :end_of_recursion_callback) end | | | | / returning from Recurse::some_recursive_function | | | / returning from Recurse::some_recursive_function | | / returning from Recurse::some_recursive_function | / returning from Recurse::some_recursive_function
Unroller shows us all the code being executed, the current line and the depth of the function in the stacktrace.
This kind of output can come quite in handy when debugging complicated situations like ActiveRecord filter chains.
More information on Unroller is found at http://unroller.rubyforge.org/.
Gepost in hor | 0 reacties
$ 3.0.0.beta2
Stephan Kaag di 06 apr 10
It took longer than they thought, but then again, what doesn’t? The second beta release of Rails 3.0 is released and hopefully the last stop before a release candidate.
You can install beta 2 and try it out with new and existing applications. (gem install rails —prerelease after you make sure you’re on Ruby Gems 1.3.6 with gem update —system).
Gepost in hor | 0 reacties
Itsy bitsy monad
Jeroen Bulters wo 31 mrt 10
Functional programming has been sort of a hype lately. Therefore I thought it would be nice to try and apply some concepts from functional programming languages to Ruby (and, ergo: Rails).
One of my personal best friends in Ruby is Mr. NilClass (not really), he always makes me add stuff to my if statements to check if he’s there. So, I’m constantly doing stuff like:
if (customer && customer.address && customer.address.zipcode)
Sure, not to big of a deal, but I just don’t like it.
Several functional programming languages know a concept known as Monad’s. I’m not going to give an introduction to Monad’s (read a good one at moonbase), but I can give a useable monad implementation in Ruby to illustrate the concept.
Monad’s basically wrap an object in a container, allow you to perform actions on it and – when you’re done playing – unwrap the resultant value from the monad.
So, after constructing the monad, and connecting some of the functionality to the Ruby Object class. I should be able to do:
any_object.if_possible?.other.value #=> 'the value I put in here' nil.if_possible?.other.value #=> nil any_object.if_possible?.nil.value #=> nil
All without yielding any exceptions.
Let’s start with adding the if_possible? method to wrap our object in a monad.
class Object def if_possible? Monad::Maybe.new(self) end end
Note: This monad is actually called the Maybe monad in a.o. Haskell
Now, we create the monad itself (nicely in the Monad module). Please note that the mentioned unwrapping is achieved through the attr_accessor and that you should choose a more semantic name for it.
module Monad class Maybe # Unwrapping through the accessor attr_accessor :value def initialize val @value = val end def monadBind proc if @value != nil # We get the result, and rewrap # that in a the Maybe monad again. proc.call.if_possible? else self end end def method_missing(method_name, *args) monadBind(Proc.new {@value.send(method_name, *args)}) end end end
Now let’s try this out with the following file:
class Test1 attr_accessor :other def initialize(other) @other = other end end class Test2 attr_accessor :value def initialize(value) @value = value end end
Load it into irb (or put the following in the same file) and try this:
value = Test2.new(true) working = Test1.new(value) puts working.other.value puts working.if_possible?.other.value.value puts nil.if_possible?.other.value
When run, it produces the following output, without throwing exceptions:
[bulters@~/monadic_art]$ ruby monad.rb true true nil
So, what did we do? Basically, we constructed a nicer way to check for nil’s, and propagating the handling of it back to our program.
The line
if (customer && customer.address && customer.address.zipcode)
can now be written as:
if(customer.if_possible?.address.zipcode.value)
which is – in my opinion – not only shorter, but also a bit easier on the eyes.
Gepost in hor | 1 reactie
Welcome to Holland On Rails
This weblog is the official Ruby techblog from the guys at Holder, a Ruby development company. Holder is also the company behind the RubyAndRails Europe Conference in Amsterdam.Recente Jobs
Bekijk alle jobs »»
Gereedschapskist
Onmisbare tools vooriedere developer!
- Ruby On Rails
Framework voor de web 2.0 developer. Eindelijk vooruitgang! - TextMate
Editor for true pro's
Typ, tab, top :-)
Nee, niet voor Win. - Made On A Mac
En nou is het over met die saaie grijze Windows bak van je!
Auteurs op deze site
Chris Obdam
'Less is more' evangelist, past dit ook dagelijks toe op zijn tandenborstel.Chiel Wester
Snelheidswonder op Ruby wielen. Leuk om mee te pair-programmen ;-)