Showing posts with label activesupport. Show all posts
Showing posts with label activesupport. Show all posts

Tuesday, November 13, 2007

Rails: Enumerable#sum

Documentation
Calculates a sum from the elements. Examples:

payments.sum { |p| p.price * p.tax_rate }
payments.sum(&:price)

This is instead of payments.inject { |sum, p| sum + p.price }

Also calculates sums without the use of a block:

[5, 15, 10].sum # => 30

The default identity (sum of an empty list) is zero. However, you can override this default:

[].sum(Payment.new(0)) { |i| i.amount } # => Payment.new(0)
Usage
The Enumerable#sum method does exactly what you would expect: Sum the elements of the array.

Test

require 'rubygems'
require 'active_support'
require 'test/unit'
require 'dust'

unit_tests do
test "sum the numbers from the array" do
grades = [50, 55, 67, 62, 71, 89, 84, 85, 99]
assert_equal 662, grades.sum
end
end

Monday, November 12, 2007

Rails: Enumerable#group_by

Documentation
Collect an enumerable into sets, grouped by the result of a block. Useful, for example, for grouping records by date.

e.g.
  latest_transcripts.group_by(&:day).each do |day, transcripts|
p "#{day} -> #{transcripts.map(&:class) * ', '}"
end
"2006-03-01 -> Transcript"
"2006-02-28 -> Transcript"
"2006-02-27 -> Transcript, Transcript"
"2006-02-26 -> Transcript, Transcript"
"2006-02-25 -> Transcript"
"2006-02-24 -> Transcript, Transcript"
"2006-02-23 -> Transcript"
Usage
The Enumerable#group_by method is helpful for grouping elements of an Enumerable by an attribute or an arbitrary grouping. The documentation provides a good example of how to group by an attribute; however, the group_by method can be used logically group by anything returned from the block given to group_by.

Test

require 'rubygems'
require 'active_support'
require 'test/unit'
require 'dust'

unit_tests do
test "group by grades" do
grades = [50, 55, 60, 62, 71, 83, 84, 85, 99]
expected = {"A"=>[99], "B"=>[83, 84, 85], "C"=>[71], "D"=>[60, 62], "F"=>[50, 55]}
actual = grades.group_by do |grade|
case
when grade < 60 then "F"
when grade < 70 then "D"
when grade < 80 then "C"
when grade < 90 then "B"
else "A"
end
end
assert_equal expected, actual
end
end

Sunday, November 11, 2007

Rails: Enumerable#index_by

Documentation
Convert an enumerable to a hash. Examples:

people.index_by(&:login)
=> { "nextangle" => , "chade-" => , ...}
people.index_by { |person| "#{person.first_name} #{person.last_name}" }
=> { "Chade- Fowlersburg-e" => , "David Heinemeier Hansson" => , ...}
Usage
I've used Enumerable#index_by for 2 different reasons recently. In one instance I needed faster access to find an element in an array. We found that pulling something out of a hash was faster than using the find method of array. We did a few benchmarks similar to the contrived examples below.
array = [1..100].to_a
hash = array.index_by { |element| element }
array_bm = Benchmark.measure do
array.find { |element| element = 99 }
end
hash_bm = Benchmark.measure do
hash.include? 99
end

p array_bm.real # => 1.382
p hash_bm.real # => 1.001
note: we couldn't use the include? method for our particular instance, so I left it out of the contrived example.

The benchmarks for our project revealed even larger gains, thus it made sense to convert our array to a hash and work with that instead of the array.

The other usage we found for index_by was to utilize the fact that index_by overwrites the value instead of appending (which group_by does). We had a list of scores and wanted to group them together. The group_by method could handle that case; however, we only wanted to keep track of the highest score per group. The test below shows an example where a list of grades can be grouped by grade letter and the highest score per grade letter.

Test

require 'rubygems'
require 'active_support'
require 'test/unit'
require 'dust'

unit_tests do
test "index by highest numeric per grade level" do
grades = [50, 55, 67, 62, 71, 89, 84, 85, 99]
expected = {"A"=>99, "B"=>89, "C"=>71, "D"=>67, "F"=>55}
actual = grades.sort.index_by do |grade|
case
when grade < 60 then "F"
when grade < 70 then "D"
when grade < 80 then "C"
when grade < 90 then "B"
else "A"
end
end
assert_equal expected, actual
end
end

Saturday, November 10, 2007

Rails: Integer#even?

Documentation
None

Usage
The Integer#even? method is helpful when adding zebra striping to views.

For example:
  <% @customers.each_with_index do |customer, index| %>
<div style="color:<%= index.even? ? "white" : "gray" %>">
<%= customer.name %>
</div>
<% end %>

Test

require 'rubygems'
require 'active_support'
require 'test/unit'
require 'dust'

unit_tests do
test "10 is even?" do
assert_equal true, 10.even?
end
end

Friday, November 09, 2007

Rails: String#each_char

Documentation
Yields a single-character string for each character in the string. When $KCODE = ‘UTF8’, multi-byte characters are yielded appropriately.
Usage
The String#each_char method is nice for iterating through a string, one character at a time. I generally use regex for string manipulation; however, when context within the string matters, each_char is helpful.

Test

require 'rubygems'
require 'active_support'
require 'test/unit'
require 'dust'

unit_tests do
test "each_char can be used to strip every other charater" do
strip, result = true, ""
"hello world".each_char do |char|
result << char if strip
strip = !strip
end
assert_equal "hlowrd", result
end
end

Thursday, November 08, 2007

Rails: Hash#diff

Documentation
None

Usage
The Hash#diff method is helpful for determining the difference between two hashes.

note: The receiver matches on both keys and values. If the pair is not matched it be returned. (for example: {:a => 1, :b => 3}.diff({:a=>2}) # => {:a=>1, :b=>3})

Test

require 'rubygems'
require 'active_support'
require 'test/unit'
require 'dust'

unit_tests do
test "find the difference between two hashes" do
assert_equal({:b=>3}, {:a => 1, :b => 3}.diff({:a=>1}))
end
end

Wednesday, November 07, 2007

Rails: String#constantize

Documentation
Constantize tries to find a declared constant with the name specified in the string. It raises a NameError when the name is not in CamelCase or is not initialized.

Examples
  • "Module".constantize #=> Module
  • "Class".constantize #=> Class
Usage
Constantize is definitely the most used String method that I utilize while metaprogramming.

Test

require 'rubygems'
require 'active_support'
require 'test/unit'
require 'dust'

unit_tests do
class Klass
end

test "constantize a string representation of a class" do
assert_equal Klass, "Klass".constantize
end
end

Tuesday, November 06, 2007

Rails: String#classify

Documentation
Create a class name from a table name like Rails does for table names to models. Note that this returns a string and not a Class. (To convert to an actual class follow classify with constantize.)

Examples
  • "egg_and_hams".classify #=> "EggAndHam"
  • "post".classify #=> "Post"
Usage
The classify method is helpful when metaprogramming. I generally replace "strings".singularize.camelize with "strings".classify (and the classify implementation calls singularize and camelize for me).

Test

require 'rubygems'
require 'active_support'
require 'test/unit'
require 'dust'

unit_tests do
test "singularize and camelize a string via classify" do
assert_equal "Name", "names".classify
end
end

Monday, November 05, 2007

Rails: String#singularize

Documentation
The reverse of pluralize, returns the singular form of a word in a string.

Examples
  • "posts".singularize #=> "post"
  • "octopi".singularize #=> "octopus"
  • "sheep".singluarize #=> "sheep"
  • "word".singluarize #=> "word"
  • "the blue mailmen".singularize #=> "the blue mailman"
  • "CamelOctopi".singularize #=> "CamelOctopus"
Usage
I generally use singularize when metaprogrammming to convert from a potentially plural version of a class name to something that I know can be constantized.

Test

require 'rubygems'
require 'active_support'
require 'test/unit'
require 'dust'

unit_tests do
test "change plural word to singular word" do
assert_equal "class_name", "class_names".singularize
end
end

Sunday, November 04, 2007

Rails: String#pluralize

Documentation
Returns the plural form of the word in the string.

Examples
  • "post".pluralize #=> "posts"
  • "octopus".pluralize #=> "octopi"
  • "sheep".pluralize #=> "sheep"
  • "words".pluralize #=> "words"
  • "the blue mailman".pluralize #=> "the blue mailmen"
  • "CamelOctopus".pluralize #=> "CamelOctopi"
Usage
I generally use pluralize for creating nice messages for users. The pluralize method can also be helpful for metaprogramming when converting from a class name to a table name.

Test

require 'rubygems'
require 'active_support'
require 'test/unit'
require 'dust'

unit_tests do
test "change singular word to plural word" do
assert_equal "names", "name".pluralize
end
end

Saturday, November 03, 2007

Rails: String#camelize

Documentation
By default, camelize converts strings to UpperCamelCase. If the argument to camelize is set to ":lower" then camelize produces lowerCamelCase.

camelize will also convert ’/’ to ’::’ which is useful for converting paths to namespaces

Examples
  • "active_record".camelize #=> "ActiveRecord"
  • "active_record".camelize(:lower) #=> "activeRecord"
  • "active_record/errors".camelize #=> "ActiveRecord::Errors"
  • "active_record/errors".camelize(:lower) #=> "activeRecord::Errors"
Usage
I generally use camelize when metaprogrammming to convert from a underscored version of a class name.

Test

require 'rubygems'
require 'active_support'
require 'test/unit'
require 'dust'

unit_tests do
test "change underscored word to camelized word" do
assert_equal "AClassName", "a_class_name".camelize
end
end

Friday, November 02, 2007

Rails: Hash#assert_valid_keys

Documentation
None

Usage
Hash#assert_valid_keys gives you the ability to verify that each of the keys in the Hash are expected. For example, if you take an options Hash as an argument to a method you may want to validate that only expected options are passed as part of the hash; assert_valid_keys gives you the ability to list the keys you expect.

Test

require 'rubygems'
require 'active_support'
require 'test/unit'
require 'dust'

unit_tests do
test "raise argument error on unexpected key" do
assert_raises ArgumentError do
{:invalid_key => :a, :valid_key => :b}.assert_valid_keys(:valid_key)
end
end
end

Thursday, November 01, 2007

Rails: Array#to_sentence

Documentation
Converts the array to comma-seperated sentence where the last element is joined by the connector word. Options:
  • :connector: The word used to join the last element in arrays with two or more elements (default: "and")
  • :skip_last_comma: Set to true to return "a, b and c" instead of "a, b, and c".
Usage
Array#to_sentence is perfect for joining information stored in an array that needs to be presented in a human readable format (e.g. an array of errors).

Test

require 'rubygems'
require 'active_support'
require 'test/unit'
require 'dust'

unit_tests do
test "words are joined nicely" do
expected = "one, two, and three"
assert_equal expected, ['one', 'two', 'three'].to_sentence
end
end

2 weeks of ActiveSupport

Recently I was browsing ActiveSupport and noticed a few methods that I wasn't, but should have been using. This led me to the idea of doing some quick entries on the various methods of ActiveSupport that may not get as much use as they should. So, following this entry, I'll be publishing something short every day for 2 weeks with information on an ActiveSupport method.

*30 days became 2 weeks after several complaints. If there are methods of ActiveSupport that I didn't get to, I encourage you to do a few quick blog entries and leave links in comments. If enough come through I'll do a follow up with links to your blog entries.