Tuesday, November 13, 2007
Ruby: Time::is
Mocha is fantastic for unit testing, but I usually try to avoid requiring it while functional testing. In general this works, but Time.now is something that I occasionally like to fix even while functional testing. To solve the problem, within a functional test helper I load a time_extensions.rb file that defines a Time::is method. The Time::is method is useful for freezing time at a certain point and executing a block of code. When the block of code finishes the Time.now method is returned to it's original implementation.
The example below is how I usually solve the described problem.
The example below is how I usually solve the described problem.
end
end
metaclass.class_eval do
define_method :now do
new_time
end
end
yield
end
end
end
Time.is(Time.now) do
Time.now # => Tue Nov 13 19:31:46 -0500 2007
sleep 2
Time.now # => Tue Nov 13 19:31:46 -0500 2007
end
Time.is("10/05/2006") do
Time.now # => Thu Oct 05 00:00:00 -0400 2006
sleep 2
Time.now # => Thu Oct 05 00:00:00 -0400 2006
end
Labels: functional testing, Time.now
Rails: Enumerable#sum
Documentation
The Enumerable#sum method does exactly what you would expect: Sum the elements of the array.
Test
UsageCalculates 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)
The Enumerable#sum method does exactly what you would expect: Sum the elements of the array.
Test
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
endLabels: activesupport, rails
Monday, November 12, 2007
Rails: Enumerable#group_by
Documentation
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
Collect an enumerable into sets, grouped by the result of a block. Useful, for example, for grouping records by date.Usage
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"
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
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
endLabels: activesupport, rails
Ruby: Testing Private Methods
Jason Rudolph recently wrote about Testing Private Methods in Ruby. Before I continue, it's probably a good idea to note that I rarely test private methods. I prefer to test through the public API. However, there are times when life is easier if you write a few tests for a private method or two.
The solution highlighted by Jason (original implementation from Evan Phoenix) is nice from a maintainability perspective since it encapsulates changing the behavior of the class within the test. However, it's a bit verbose for my taste.
Reading the entry I couldn't help but think that gaining temporary access to a private method for testing seems like something that can be handled by a general solution instead.
Here's how I would have solved the problem.
The solution highlighted by Jason (original implementation from Evan Phoenix) is nice from a maintainability perspective since it encapsulates changing the behavior of the class within the test. However, it's a bit verbose for my taste.
Reading the entry I couldn't help but think that gaining temporary access to a private method for testing seems like something that can be handled by a general solution instead.
Here's how I would have solved the problem.
private
" victims are no longer with us."
end
end
saved_private_instance_methods = self.private_instance_methods
self.class_eval {public *saved_private_instance_methods }
yield
self.class_eval {private *saved_private_instance_methods }
end
end
unit_tests do
test "kill returns a murder string" do
Ninja.publicize_methods do
assert_equal '3 victims are no longer with us.', Ninja.new.kill(3)
end
end
endLabels: ruby, testing private methods
Sunday, November 11, 2007
Rails: Enumerable#index_by
Documentation
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.
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
UsageConvert 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" => , ...}
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_anote: we couldn't use the
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
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
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
endLabels: activesupport, rails
Saturday, November 10, 2007
Rails: Integer#even?
Documentation
None
Usage
The Integer#even? method is helpful when adding zebra striping to views.
For example:
Test
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
unit_tests do
test "10 is even?" do
assert_equal true, 10.even?
end
endLabels: activesupport, rails
Friday, November 09, 2007
Rails: String#each_char
Documentation
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
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
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
endLabels: activesupport, rails
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
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
unit_tests do
test "find the difference between two hashes" do
assert_equal({:b=>3}, {:a => 1, :b => 3}.diff({:a=>1}))
end
endLabels: activesupport, rails
Despised Software Luminaries
This morning I spent some time thinking about how software luminaries are generally loved or hated.
I've always been confused by people who really dislike Martin Fowler. Personally, I find Martin to be quite nice, but even if I didn't I would find it hard to disregard his passion for improving software development.
Obie Fernandez is another luminary who generally evokes love or hate. I'm friends with Obie as well as people who dislike Obie. Obie detractors often ask: How can you put up with him? The question is mostly targeted at Obie's passionate communication style. I've always thought that what Obie has to say is what's important, so I don't really care how he chooses to communicate it.
As I've gotten to know an increasing number of luminaries I noticed that things don't change at the top either: several of the luminaries seem to love and hate each other.
Why is it that software luminaries elicit such passionate feelings? I believe it's because software development (at an advanced level) is art. It's hard to find developers who can agree on architecture and it's hard to find artists who can agree on the best painting of all time. There is no right answer, it's contextual and subjective.
I also believe that luminaries (unconsciously) perpetuate the disdain with their passionate personalities. For example, a Martin Fowler averse developer once told me that Martin lives in a Java only world. If you read Martin's material you know that isn't the case; however, Martin does use Java examples very often. I don't think Martin uses Java because he prefers Java, I believe that Martin is passionate about reaching as many people as possible and therefore must use a widely known language. Unfortunately, the developer didn't see it from that perspective (I believe) because he was so focused on Ruby being better than Java that he was ready to dismiss anything pertaining to Java.
Software is an art and luminaries are passionate, I don't expect either of these things to change in the near future. Thus, I expect the disdain to remain as well, but perhaps being aware of the origin of the dislike can lead to a bit more tolerance within our passionate, artistic communities.
I've always been confused by people who really dislike Martin Fowler. Personally, I find Martin to be quite nice, but even if I didn't I would find it hard to disregard his passion for improving software development.
Obie Fernandez is another luminary who generally evokes love or hate. I'm friends with Obie as well as people who dislike Obie. Obie detractors often ask: How can you put up with him? The question is mostly targeted at Obie's passionate communication style. I've always thought that what Obie has to say is what's important, so I don't really care how he chooses to communicate it.
As I've gotten to know an increasing number of luminaries I noticed that things don't change at the top either: several of the luminaries seem to love and hate each other.
Why is it that software luminaries elicit such passionate feelings? I believe it's because software development (at an advanced level) is art. It's hard to find developers who can agree on architecture and it's hard to find artists who can agree on the best painting of all time. There is no right answer, it's contextual and subjective.
I also believe that luminaries (unconsciously) perpetuate the disdain with their passionate personalities. For example, a Martin Fowler averse developer once told me that Martin lives in a Java only world. If you read Martin's material you know that isn't the case; however, Martin does use Java examples very often. I don't think Martin uses Java because he prefers Java, I believe that Martin is passionate about reaching as many people as possible and therefore must use a widely known language. Unfortunately, the developer didn't see it from that perspective (I believe) because he was so focused on Ruby being better than Java that he was ready to dismiss anything pertaining to Java.
Software is an art and luminaries are passionate, I don't expect either of these things to change in the near future. Thus, I expect the disdain to remain as well, but perhaps being aware of the origin of the dislike can lead to a bit more tolerance within our passionate, artistic communities.
Labels: luminaries, software is art
Wednesday, November 07, 2007
Rails: String#constantize
Documentation
Constantize is definitely the most used String method that I utilize while metaprogramming.
Test
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.Usage
Examples
- "Module".constantize #=> Module
- "Class".constantize #=> Class
Constantize is definitely the most used String method that I utilize while metaprogramming.
Test
unit_tests do
end
test "constantize a string representation of a class" do
assert_equal Klass, "Klass".constantize
end
endLabels: activesupport, rails
Tuesday, November 06, 2007
Rails: String#classify
Documentation
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
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.)Usage
Examples
- "egg_and_hams".classify #=> "EggAndHam"
- "post".classify #=> "Post"
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
un