Flowdock

Recent notes

RSS feed
February 12, 2009
3 thanks

Other regular-expression modifiers

Likewise you can set Regexp::IGNORECASE directly on the regexp with the literal syntax:

/first/i
# This will match "first", "First" and even "fiRSt"

Even more modifiers

  • o – Perform #{} interpolations only once, the first time the regexp literal is evaluated.

  • x – Ignores whitespace and allows comments in * regular expressions

  • u, e, s, n – Interpret the regexp as Unicode (UTF-8), EUC, SJIS, or ASCII. If none of these modifiers is specified, the regular expression is assumed to use the source encoding.

Literal to the rescue

Like string literals delimited with %Q, Ruby allows you to begin your regular expressions with %r followed by a delimiter of your choice.

This is useful when the pattern you are describing contains a lot of forward slash characters that you don’t want to escape:

%Q(http://)
# This will match "http://"
February 12, 2009
4 thanks

Literal syntax

As you propably know you can create an Array either with the constructor or the literal syntax:

Array.new == []
# => true

But there is also another nice and concise literal syntax for creating Arrays of Strings:

["one", "two", "three"] == %w[one two three]
# => true

You can use any kind of parenthesis you like after the %w, either (), [] or {}. I prefer the square brackets because it looks more like an array.

February 12, 2009
2 thanks

Use this!

You should raise your own ArgumentError in methods to notify users of your class, if you think certain kinds of arguments aren’t acceptable.

def transfer_money(amount)
  unless amount.is_a?(Number)
    raise ArgumentError.new("Only numbers are allowed")
  end
  # ... Do the actual work
end
February 12, 2009
3 thanks

Useful scenario

This can be quite useful, for example when writing a command line script which takes a number of options.

Example

Let’s say you want to make a script that can make the basic CRUD operations. So want to be able to call it like this from the command line:

> my_script create
> my_script delete

The following script allows you to use any abbreviated command as long as it is unambiguous.

# my_script.rb
require 'abbrev'

command = ARGV.first
actions = %w[create read update delete]
mappings = Abbrev::abbrev(actions)
puts mappings[command]

That means you can call it like this:

> my_script cr
> my_script d

And it will print:

create
delete
February 10, 2009
8 thanks

Security issue with non-HTML formats

Please note that using default to_xml or to_json methods can lead to security holes, as these method expose all attributes of your model by default, including salt, crypted_password, permissions, status or whatever you might have.

You might want to override these methods in your models, e.g.:

def to_xml
  super( :only => [ :login, :first_name, :last_name ] )
end

Or consider not using responds_to at all, if you only want to provide HTML.

February 10, 2009
0 thanks

Cheat Sheet

I have written a short introduction and a colorful cheat sheet for Perl Compatible Regular Expressions (PCRE) as used by Ruby’s Regexp class:

http://www.bitcetera.com/en/techblog/2008/04/01/regex-in-a-nutshell/

February 10, 2009
0 thanks

Cheat Sheet

I have written a short introduction and a colorful cheat sheet for Perl Compatible Regular Expressions (PCRE) as used by Ruby’s Regexp class:

http://www.bitcetera.com/en/techblog/2008/04/01/regex-in-a-nutshell/

February 10, 2009
3 thanks

Cheat Sheet

I have written a short introduction and a colorful cheat sheet for Perl Compatible Regular Expressions (PCRE) as used by Ruby’s Regexp class:

http://www.bitcetera.com/en/techblog/2008/04/01/regex-in-a-nutshell/

February 10, 2009
2 thanks
February 10, 2009
0 thanks

Output format

This outputs date & time in format of yyyy-MM-ddThh-mm-ssZZZ. All values are preceded with 0 if less than 10. Hours are in 0..23 range. Timezone is sticked at the end. Watch out for capital T in the middle :)

February 9, 2009
5 thanks
February 9, 2009
1 thank

:foreign_type option

I’m not sure if this has always been around but in 2.3, belongs_to takes a :foreign_type option on polymorphic associations. This behaves the same way as :foreign_key but for the type field.

February 9, 2009
2 thanks

Calculating on an enumerable

Inject can easily be used to sum an enumerable or to get the product of it

[100, 200, 1000].inject(0) { |sum, value| sum += value } # => 1300
[100, 200, 1000].inject(1) { |sum, value| sum *= value } # => 20000000

# You can access members and move down in the data structures, too
points.inject(0) { |sum, point| sum += point.y }

In the case of the first two examples, an easier way to do it in Ruby 1.9 is to use reduce:

[100, 200, 1000].reduce :+ # => 1300
[100, 200, 1000].reduce :* # => 20000000

Look at reduce for more examples on how to use this.

February 8, 2009
0 thanks

Can be used on classes, too

For example:

class C
  protected
    def foo
    end 
end
p C.protected_instance_methods(false)

outputs:

["foo"]
February 7, 2009 - (>= v2.2.1)
1 thank

Documentation

Good docs can be found here: http://www.artweb-design.de/2008/7/18/the-ruby-on-rails-i18n-core-api

See also: http://rails-i18n.org/wiki for an extensive list of resources.

February 7, 2009 - (>= v2.2.1)
3 thanks

Deprecated

This method is deprecated. You should use:

I18n.translate('activerecord.errors.messages')
February 6, 2009 - (>= v2.1.0)
1 thank

Whacky edge case

The above works great as long as you select the primary key of the owning assocations.

preload_associations calls a group_by on that object so if there is no primary key attributed filled out it will reduce the records to 1 object. ex: rows = foo.find(:all,:select=>“boo.id, foo.name, foo.age, count(DISTINCT foo.id)”, :group=>“foo.name,foo.age having count( DISTINCT foo.id) > 1”,:joins=>“INNER JOIN bar.foo on bar.foo_id = foo.id”)

preload_assications(rows,:bar)

rows.first.bar.name #=> sql call already made in preload rows.last.bar.name #=> just made another sql call to get bar

fix: :select=>“foo.id, boo.id, foo.name, foo.age, count(DISTINCT foo.id)”

now preload_associations will include all the ids found instead of just the 1st one.

February 5, 2009
1 thank

Weird method...

Takes three params:

- a Class constant (has to be an existing class)
- a "tag" param that, if set to "tag:yaml.org,2002:binary" will call unpack("m") on the third parameter, val; any other values for tag are ignored
- val can be a Hash or a String; if it's a string it is wrapped in a hash {'str' => val}, other wise...
  1. an instance of klass is allocated

  2. an instance of string is initialized, with the val parameter, and bound to the class context

  3. for each key in val (if any!), set instance variables in the instantiated class

So, what does this method do, a part from making my eyes hurt? It loads a yaml file and instantiates a class and sets the ivars found in the yaml file. Sorta.

It is probably the worst code I have ever seen in the ruby standard libs. WTF!!

:)

February 4, 2009
1 thank

How I use Optimistic Locking

I have used Optimistic locking often, but usually I only need it in one or two places in the codebase, not everywhere an object is saved whose model has a lock_version column. So what I usually end up doing is using a little module I wrote called OptimisticallyLockable (awesome name right?). Here it is:

module OptimisticallyLockable

  def self.included(receiver)
    receiver.lock_optimistically = false
    receiver.class_eval do

      def self.with_optimistic_locking
        original_lock = self.lock_optimistically
        self.lock_optimistically = true

        begin
          yield
        ensure
          self.lock_optimistically = original_lock
        end
      end

    end
  end

end

When included in a model that has a lock_version column it will turn off optimistic locking. Then when you want to actually use optimistic locking you can just use the with_optimistic_locking method like this:

class Blog
   include OptimisticallyLockable

   def do_something_destructive!
     self.class.with_optimistic_locking do
        #  do something important here
     end
   end                                
end
February 4, 2009
1 thank

RE: Careful when building gems

I found out a way to combine using RDoc::usage when you are building a gem. By ripping out the code from the usage method you can create your own version which opens the correct file.

In my case, I skipped the file reading and just put the usage information in a string and used that directly.

Here is my code:

$usage = %Q{
 = Synopsis
 ...
 = Usage
 ...

 == Options
 ...
 }

 # Shamefully stolen from RDoc#usage. We cannot use RDoc::usage because
 # RubyGems will call this from a wrapper, and #usage is hardcoded to look
 # at the top-level file instead of the current one. I have changed this
 # code to instead just parse a string.
 def usage_and_exit!
   markup = SM::SimpleMarkup.new
   flow_convertor = SM::ToFlow.new

   flow = markup.convert($usage, flow_convertor)

   options = RI::Options.instance
   formatter = options.formatter.new(options, "")
   formatter.display_flow(flow)

   exit(0)
 end

Look in usage_no_exit if you want to rip stuff out. It’s up to you how and if you implement this at all, but it’s a shortcut to use the RDoc code and formatting. Do also consider doing the formatting yourself by hand and just output that string instead.

February 4, 2009
0 thanks
February 4, 2009
3 thanks

Multiline regexps

A shortcut for multiline regular expressions is

/First line.*Other line/m

(notice the trailing /m)

For example:

text = <<-END
  Hello world!
  This is a test.
END

text.match(/world.*test/m).nil?  #=> false
text.match(/world.*test/).nil?   #=> true
February 4, 2009
0 thanks

usage example

code

class MyModel < ActiveRecord::Base
  def created_today?
    self.created_on.to_date == Date.today
  end
end
February 4, 2009
0 thanks

Careful when building gems

If you are building a gem with executables and you think about using RDoc::Usage for facilitating the --help message, think again.

usage and usage_no_exit is hardcoded to look for the initial comment in the top level file being executed, which is normally fine, but when installing a gem, RubyGems will generate a wrapper executable for you, and usage will therefore look in that wrapper file for the comment instead of your own file.

The methods contain too much code to be easily monkey patched too. Hopefully, this will be fixed in a later version.

February 3, 2009
3 thanks

Possible gotcha

Please note that exists? doesn’t hold all the conventions of find, i.e. you can’t do:

Person.exists?(:conditions => ['name LIKE ?', "%#{query}%"]) # DOESN'T WORK!
February 3, 2009
0 thanks

Getting functionality from instances

If you want to get this functionality from instances of the models too, you can easily monkey patch rails to allow this. This is only semi-bad practice, AFAIK.

In config/initializers/overrides.rb:

#
# Wrapper for @model.human_attribute_name -> Model.human_attribute_name
#
class ActiveRecord::Base
  def human_attribute_name(*args)
    self.class.human_attribute_name(*args)
  end
end

Now, why is this bad? Because we change a core class, and that makes maintainability a little bit harder since new developers will not know about this.

The good part is that is such a small thing and as long as human_attribute_name exists in the class, this extension will work.

Example usage:

# index.html.haml
%th= User.human_attribute_name('login')
%th= User.human_attribute_name('email')
# ...

# show.html.haml
%p
  %strong= "#{@user.human_attribute_name('login')}: "
  = @user.login

In this example, about nothing was gained at all, really. A better example is when you are building helpers to do stuff like displaying model attributes for you and whatnot. Examples for this would be far too huge to show off here, but basically, you avoid having to do stuff like this:

if options.include? :model
  model = options[:model]
  model = model.class unless model.is_a? Class
  model.human_attribute_name(field)
else
  # ...
end

and you want to keep your views clean (@user vs. @user.class)

February 3, 2009
3 thanks

Nothing here

You’re probably looking for I18n::Backend::Simple.

February 3, 2009
4 thanks

This method will still rewrite all the values of the table

Even if you update only a small boolean flag on your record, update_attribute will generate an UPDATE statement that will include all the fields of the record, including huge BLOB and TEXT columns. Take this in account.

February 2, 2009
1 thank

usage

code

@items = Item.find(:all)
@items.should have_at_least(1).item