Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Can we get an alias for it_should_behave_like? #74

Closed
wincent opened this Issue · 15 comments

2 participants

@wincent

One thing which has always bugged me about it_should_behave_like is that it requires me to describe my behaviors in terms of a concrete "thing", as opposed to an abstract thing. ie. it_should_behave_like "this thing" or it_should_behave_like "that thing"

I often find it difficult to describe groups of behavior in this way. For example, I have methods in my ApplicationController and I specify their behavior in shared example groups which I then included in the subclasses, but then I find it difficult to name the group and wind up with a bunch of declarations like:

it_should_behave_like "(some aspect of) ApplicationController" # or
it_should_behave_like "ApplicationController (some method name)"

What do you think of providing one alias that allows us to labelled shared examples as abstract behaviors rather than concrete things. For example, it_has_behavior.

Then I could write things like:

it_has_behavior 'taggability' # or 'tagging', if you prefer
it_has_behavior 'sortability' # or 'sorting, if you prefer
it_has_behavior 'versioning'

Instead of:

it_should_behave_like 'a taggable model'
it_should_behave_like 'a commentable model'
it_should_behave_like 'a versioned model'

At least for me, the former is preferable, and in line with the trend to write out examples without the "should"; ie:

it 'does something'

Rather than

it 'should do something'

What do you think?

@dchelimsky
Owner

I'm not sure I'd want to add this, but ....

There is a method on ExampleGroup called alias_example_to which we use like this internally:

alias_example_to :pending, :pending => true

And that lets you say:

pending "example" do

And it's the same as saying:

example "example", :pending => true do

What if we added alias_it_should_behave_like_to(method_name, string_prefix), so you'd be able to say:

ExampleGroup.alias_it_should_behave_like_to(:it_has_behaviour, "has behaviour")

describe "something specific" do
  it_has_behaviour "sortability" do
    let(:sortable) { SomethingSpecific.new }
  end
end

Which would produce output:

something specific
  has behaviour: sortability
    # sortability examples here
@wincent

Looks nice. I hadn't thought about the formatting of the output because in general I find the existing output to be fine (ie. the "it should behave like" text which is sometimes problematic for me doesn't appear in the output, only the included examples do).

If you think it would be a good idea, then sure.

All in all, I don't think it's a bad idea to expose this (and perhaps other) aliasing methods. All my specs are in English, but I am sure there are a lot of developers out there working in other languages who wouldn't mind having an easy way to alias some of those keywords to something else. But I guess that is a subject for another ticket. Don't want to overload this one.

@dchelimsky
Owner

Actually, with the recent changes, "it should behave like" DOES show up in the output text, which I think is a huge win.

I'll give this aliasing some thought.

@wincent

Ah, well if it appears in the output like that, yeah, it would be pretty essential to offer the override that you proposed above, otherwise there's no point in aliasing.

As it reads in those examples I find it a bit incongruous:

  Array
    it should behave like a collection object
      initialized with 3 items
        has three items
      #first
        returns the first item

  Set
    it should behave like a collection object
      initialized with 3 items
        has three items
      #first
        returns the first item

While the examples themselves are concise (starting with a verb) like "has three items", the "it should behave like ..." seems comparatively verbose. Would read nicer as:

  Array
    behaves like a collection object
      initialized with 3 items
        has three items
      #first
        returns the first item

  Set
    behaves like a collection object
      initialized with 3 items
        has three items
      #first
        returns the first item

ie. "behaves like" instead of "it should behave like".

@dchelimsky
Owner

ExampleGroup.alias_it_should_behave_like_to(:it_behaves_like, "behaves like") :-D

@dchelimsky
Owner

The benefit of that is that you can choose your style. Lots of people still write it "should ....", while others write it "does ....". This would serve both.

@wincent

Seems like a plan.

@dchelimsky
Owner

You wanna fire that up?

@wincent

I'll have a try.

@wincent

Ok, first cut at pushed to this branch:

http://github.com/wincent/rspec-core/commits/issue-74

Specifically this commit:

http://github.com/wincent/rspec-core/commit/8ff5f2d05f37495b2b724535488fceca8bab0466

This commit basically just to show that it works. I'd like to remove the duplication, however, wherein the alias_it_should_behave_like_to method contains a near-verbatim copy of the it_should_behave_like method.

Not sure which way you'd like to remove this duplication, but the way I'd do it would be something like the following:

Make a new method, similar to define_example_method, which actually includes the shared examples. This method would be called something like include_shared_examples and it would take the shared example group name, the "reporting label", and the customization block as parameters. Something like:

def include_shared_examples(name, report_label = 'it should behave like', &customization_block)
  shared_block = world.shared_example_groups[name]
  raise "Could not find shared example group named #{name.inspect}" unless shared_block

  shared_group = describe("#{report_label} #{name}", &shared_block)
  shared_group.class_eval &customization_block if customization_block
  shared_group
end

it_should_behave_like and alias_it_should_behave_like_to would then just delegate to this method, boiling down to basically:

def self.it_should_behave_like(name, &customization_block)
  include_shared_examples(name, &customization_block)
end

def self.alias_it_should_behave_like_to(new_name, report_label)
  module_eval(<<-END_RUBY, __FILE__, __LINE__)
    def self.#{new_name}(name, &customization_block)
      include_shared_examples(name, #{report_label.inspect}, &customization_block)
    end
  END_RUBY
end

Haven't actually done it yet (typed in browser, so usual disclaimers apply). What would you do?

@wincent

Yes, much better.

@dchelimsky
Owner

Cool - I'll merge that to master then.

@timcharper timcharper referenced this issue from a commit in timcharper/rspec-core
@dchelimsky dchelimsky Parse options earlier so the runner can determine whether to use drb if
it is set in an options file.

Closes #74.
a9ff5a8
@timcharper timcharper referenced this issue from a commit in timcharper/rspec-core
@wincent wincent Add alias_it_should_behave_like_to
Closes #74.
7b0d232
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.