Permalink
Browse files

Switch from overriding methods, to prepending an anonymous Module.

This has 2 benefits:
* objects don't get those weird "original foo=" methods
* we don't have to warn if you're sweeping a method that's not there (just call super!)
* it's less code: it falls out of the object model

...plus, it's cleaner.
  • Loading branch information...
danbernier committed Feb 7, 2015
1 parent e9ae059 commit 1300bdcb15ed5982a132faec152de2f3d3b09d78
Showing with 11 additions and 30 deletions.
  1. +1 −5 README.md
  2. +10 −10 lib/tiny_sweeper.rb
  3. +0 −15 spec/tiny_sweeper_spec.rb
View
@@ -70,11 +70,7 @@ Rails models are clearly the natural use-case for this. So it would make sense t
## How Does It Work?
You include the `TinySweeper` module in your class, and define some sweep-up rules on your class' attributes. It overrides your method, and defines a new method that cleans its input according to the sweep-up rule, and then calls the original method with the clean value.
"Isn't it better to generate a module for the new methods, and call `super`?"
Sure, but if you do that, the module's method is called *after* the original one. We want to clean the input *before* it gets to your method.
You include the `TinySweeper` module in your class, and define some sweep-up rules on your class' attributes. It prepends an anonymous module to your class, adds to it a method with the same name that cleans its input according to the sweep-up rule, and then passes the cleaned value to `super`.
"Why not use `after_create` or `before_save` or `before_validate` callbacks?"
View
@@ -1,16 +1,14 @@
module TinySweeper
module ClassMethods
def sweep(field_name, &sweeper)
stop_if_attribute_does_not_exist!(field_name)
stop_if_we_have_seen_this_before!(field_name)
writer_method_name = writer_method_name(field_name)
alias_method "original #{writer_method_name}", writer_method_name
define_method(writer_method_name) do |value|
clean_value = sweeper.call(value)
send("original #{writer_method_name}", clean_value)
overrides_module.module_eval do
define_method(writer_method_name) do |value|
super(sweeper.call(value))
end
end
end
@@ -22,10 +20,12 @@ def sweep_up!(instance)
private
def stop_if_attribute_does_not_exist!(field_name)
unless method_defined?(writer_method_name(field_name))
raise "There is no method named #{field_name.inspect} to sweep up!"
end
def overrides_module
@overrides_module ||= begin
mod = Module.new
prepend mod
mod
end
end
def stop_if_we_have_seen_this_before!(field_name)
View
@@ -10,13 +10,6 @@ class Contract
sweep(:name) { |n| n.upcase }
end
it 'leaves some unfortunate method names, maybe?' do
contract = Contract.new
original_writers = contract.methods.grep(/^original /).sort
expect(original_writers).to eq([:"original name=", :"original notes="])
# NB: we're not saying this is GOOD, we're just noting it.
end
it 'strips notes' do
contract = Contract.new
contract.notes = ' needs stripping '
@@ -64,14 +57,6 @@ class Contract
}.to raise_error
end
it "will bark if you sweep a method that doesn't exist" do
some_class = Class.new
some_class.send(:include, TinySweeper)
expect {
some_class.send(:sweep, :attribute, &:whatever)
}.to raise_error("There is no method named :attribute to sweep up!")
end
it "will let you sweep an inherited method" do
class BaseClass
attr_accessor :name

0 comments on commit 1300bdc

Please sign in to comment.