Skip to content
This repository was archived by the owner on Nov 30, 2024. It is now read-only.

Conversation

@cupakromer
Copy link
Member

First pass at replacing all uses of string eval per #267

I've tested on 1.8.7-p374, 1.9.3-p392, and 2.0.0-p247.

One potential issue is that I made the decision to use Module#class_exec which was only added in 1.8.7 and 1.9. I did this for two reasons:

  1. It only supports blocks (not possible to pass strings)
  2. It provides the ability to directly pass instance variables into the evaluation block, instead of having to exploit the block closure with local variables:
# Using class_exec
@klass.class_exec(@method_name) do |method_name|
  define_method(method_name) do
    # ...
  end
end

# Using class_eval
method_name = @method_name
@klass.class_eval do
  define_method(method_name) do
    # ...
  end
end

This will break 1.8.6 support. Let me know what you think.

In the majority of instances, using define_method over eval'ing a String
is better, and safer. See:

http://tenderlovemaking.com/2013/03/03/dynamic_method_definitions.html
These two methods are particularly tricky in their use of string
interpolation for the `class_eval`. To remove the string passed to
`class_eval` one of two approaches is possible:

  * Retain the `class_eval` and exploit the block closure by defining
    local variables referencing the instance variables to be used in the
    eval block
  * Switch to using `class_exec` which was introduced in 1.8.7 and 1.9.
    This allows for instance variables to be passed into the block
    creating block local variables

I choose the latter for writing cleaner code and to embrace the future
dropping of support for 1.8.6.
@coveralls
Copy link

Coverage Status

Coverage increased (+0%) when pulling d3ef19c on cupakromer:replace-string-eval into 6ef6f11 on rspec:master.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cupakromer thanks for this PR! I don't get why this raise_error got more specific in something related to changing evals to define_method type situations. What's going on here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was some interpolation going on in https://github.com/rspec/rspec-mocks/pull/340/files#L4R16. Without the more specific spec, I wasn't sure if my change to the method_name interpolation was correct.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the drop of the .inspect call I'm ok with this change to the spec

@myronmarston
Copy link
Member

First pass at replacing all uses of string eval per #267

I've tested on 1.8.7-p374, 1.9.3-p392, and 2.0.0-p247.

One potential issue is that I made the decision to use Module#class_exec which was only added in 1.8.7 and 1.9. I did this for two reasons:

It only supports blocks (not possible to pass strings)
It provides the ability to directly pass instance variables into the evaluation block, instead of having to exploit the block closure with local variables:

Using class_exec

@klass.class_exec(@method_name) do |method_name|
define_method(method_name) do
# ...
end
end

Using class_eval

method_name = @method_name
@klass.class_eval do
define_method(method_name) do
# ...
end
end
This will break 1.8.6 support. Let me know what you think.

Breaking 1.8.6 support is fine in master. We're dropping support in RSpec 3.0.

As for the class_exec idiom you used here...it's not one I'm used to seeing. It looks odd to me at first; I tend to use the class_eval idiom you listed instead. I commented on the changes before reading your summary and seeing you explained this. I think after reading your explanation, I'm fine keeping the class_exec.

Remove the instances where `class_eval` is there only to change the
value of `self` for the `define_method` message. Just send it directly
to the desired object. Use `__send__` as `define_method` is private.

Remove the superfluous instances of `to_syms`.
@coveralls
Copy link

Coverage Status

Coverage increased (+0%) when pulling 7569e3b on cupakromer:replace-string-eval into 6ef6f11 on rspec:master.

@JonRowe
Copy link
Member

JonRowe commented Jul 5, 2013

(Sorry repeating from line comment in case it gets lost)

We've already dropped support for 1.8.6 and even 2.14 doesn't work 100% with it so I don't think it's an issue with respect to this. I'm leaning towards preferring _exec given that by being explicitly we're limiting the amount of leakage than occur from using the closures.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the to_sym necessary here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Nope, your'e right. I now see it was necessary in the original due to the string interpolation (symbols are converted to strings), so the colon needed to be added back. Will remove.

@JonRowe
Copy link
Member

JonRowe commented Jul 5, 2013

Good work, I thought I'd caught most of these on my first pass through removing evals, guess not :)

❤️ ❤️ ❤️

@coveralls
Copy link

Coverage Status

Coverage remained the same when pulling 63fd8c4 on cupakromer:replace-string-eval into 6ef6f11 on rspec:master.

JonRowe added a commit that referenced this pull request Jul 5, 2013
@JonRowe JonRowe merged commit 8b5c68f into rspec:master Jul 5, 2013
@cupakromer cupakromer deleted the replace-string-eval branch July 5, 2013 23:24
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants