Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can we get an alias for it_should_behave_like? #74

Closed
wincent opened this issue Jul 17, 2010 · 15 comments
Closed

Can we get an alias for it_should_behave_like? #74

wincent opened this issue Jul 17, 2010 · 15 comments

Comments

@wincent
Copy link
Contributor

wincent commented Jul 17, 2010

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
Copy link
Contributor

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
Copy link
Contributor Author

wincent commented Jul 17, 2010

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
Copy link
Contributor

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.

@dchelimsky
Copy link
Contributor

@wincent
Copy link
Contributor Author

wincent commented Jul 17, 2010

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
Copy link
Contributor

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

@dchelimsky
Copy link
Contributor

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
Copy link
Contributor Author

wincent commented Jul 17, 2010

Seems like a plan.

@dchelimsky
Copy link
Contributor

You wanna fire that up?

@wincent
Copy link
Contributor Author

wincent commented Jul 17, 2010

I'll have a try.

@wincent
Copy link
Contributor Author

wincent commented Jul 18, 2010

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?

@dchelimsky
Copy link
Contributor

@wincent
Copy link
Contributor Author

wincent commented Jul 18, 2010

Yes, much better.

@dchelimsky
Copy link
Contributor

Cool - I'll merge that to master then.

@dchelimsky
Copy link
Contributor

timcharper pushed a commit to timcharper/rspec-core that referenced this issue Aug 19, 2011
timcharper pushed a commit to timcharper/rspec-core that referenced this issue Aug 19, 2011
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants