Thank you so much Justin. Crystal clear now. Regards,
Gustavo Delfino On May 26, 2011, at 12:05 AM, Justin Ko wrote: > Actually, the lambda approach won't work, because you're carrying state > (@index & @width) that is outside of scope in the matcher. This is what it > would look like though: > > module CustomColumnsMatchers > > RSpec::Matchers.define(:have_text) do |expected_string| > chain(:on_column, &ChainHelpers.on_column) > chain(:on_columns, &ChainHelpers.on_columns) > > match do |line| > line[@index] == expected_string.ljust(@width) > end > end > > RSpec::Matchers.define(:have_number) do |expected_number_string| > chain(:on_column, &ChainHelpers.on_column) > chain(:on_columns, &ChainHelpers.on_columns) > > match do |line| > line[@index] == expected_number_string.rjust(@width,'0') > end > end > > module ChainHelpers > def self.on_column > lambda do |colnumber| > @index = colnumber - 1 > @width = 1 > end > end > > def self.on_columns > lambda do |range| > a = range.to_a > @index = Range.new( a[0]-1, a[-1]-1 ) > @width = a[-1] - a[0] + 1 > end > end > end > > end > > > You could keep all of the state in the ChainHelpers module: > > module CustomColumnsMatchers > > RSpec::Matchers.define(:have_text) do |expected_string| > chain(:on_column, &ChainHelpers.on_column) > chain(:on_columns, &ChainHelpers.on_columns) > > match do |line| > line[ChainHelpers.index] == expected_string.ljust(ChainHelpers.width) > end > end > > RSpec::Matchers.define(:have_number) do |expected_number_string| > chain(:on_column, &ChainHelpers.on_column) > chain(:on_columns, &ChainHelpers.on_columns) > > match do |line| > line[ChainHelpers.index] == > expected_number_string.rjust(ChainHelpers.width,'0') > end > end > > module ChainHelpers > class << self > attr_accessor :index, :width > end > > def self.on_column > lambda do |colnumber| > self.index = colnumber - 1 > self.width = 1 > end > end > > def self.on_columns > lambda do |range| > a = range.to_a > self.index = Range.new( a[0]-1, a[-1]-1 ) > self.width = a[-1] - a[0] + 1 > end > end > end > > end > > > That is kinda dirty and ugly - I'd stick with the "extend" solution. > _______________________________________________ > rspec-users mailing list > rspec-users@rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users On May 25, 2011, at 12:50 PM, David Chelimsky wrote: > I'd probably do something like: > > RSpec::Matchers.define(:have_text) do |expected_string| > chain(:on_column, &HaveXXXHelpers.on_column) > chain(:on_columns, &HaveXXXHelpers.on_columns) > match do |line| > line[@index] == expected_string.ljust(@width) > end > end > > HTH, > David On May 25, 2011, at 10:37 AM, Gustavo Delfino wrote: > Hello all. Thanks to subjects, custom matchers and fluent chaining I was able > to greatly simplify my spec. But now I want to DRY my custom matchers. > > I have two custom matchers: 'have_text' and 'have_number' and both contain > exactly the same chains 'on_column' and 'on_columns'. > > Is there a way to DRY this up? > > > module CustomColumnsMatchers > > RSpec::Matchers.define(:have_text) do |expected_string| > chain(:on_column) do |colnumber| > @index = colnumber - 1 > @width = 1 > end > chain(:on_columns) do |range| > a = range.to_a > @index = Range.new( a[0]-1, a[-1]-1 ) > @width = a[-1] - a[0] + 1 > end > match do |line| > line[@index] == expected_string.ljust(@width) > end > end > > RSpec::Matchers.define(:have_number) do |expected_number_string| > chain(:on_column) do |colnumber| > @index = colnumber - 1 > @width = 1 > end > chain(:on_columns) do |range| > a = range.to_a > @index = Range.new( a[0]-1, a[-1]-1 ) > @width = a[-1] - a[0] + 1 > end > match do |line| > line[@index] == expected_number_string.rjust(@width,'0') > end > end > > end > > > Regards, > > Gustavo Delfino _______________________________________________ rspec-users mailing list rspec-users@rubyforge.org http://rubyforge.org/mailman/listinfo/rspec-users