overridable 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -4,36 +4,36 @@ Overridable is a pure ruby library which helps you to make your methods which ar
4
4
 
5
5
  ## Why?
6
6
 
7
- We all know that it's impossible for modules to override methods that are defined in classes when they are included. For example:
7
+ Some people are overusing `alias_method_chain` in their codes like what wycats mentioned in [his post][post]. One of the reasons that people like using `alias_method_chain` is because it's impossible for modules to override methods that are defined in classes when they are included. For example:
8
8
  class Thing
9
9
  def foo
10
10
  'Thing.foo'
11
11
  end
12
12
  end
13
13
 
14
- module Redef
14
+ module Extension
15
15
  def foo
16
- 'Redef.foo'
16
+ 'Extension.foo'
17
17
  end
18
18
  end
19
19
 
20
- Thing.send :include, Redef
21
- Thing.new.foo #=> Thing.foo # not Redef.foo
20
+ Thing.send :include, Extension
21
+ Thing.new.foo #=> Thing.foo # not Extension.foo
22
22
 
23
- Usually, in order to achieve that goal, we will write the Redef module like this:
24
- module Redef
23
+ In order to achieve that goal, some will write the Extension module like this:
24
+ module Extension
25
25
  def foo_with_redef
26
- 'Redef.foo'
26
+ 'Extension.foo'
27
27
  end
28
28
  # you can also do this by: alias_method_chain :foo, :redef, if you use ActiveSupport.
29
29
  alias foo_without_redef foo
30
30
  alias foo foo_with_redef
31
31
  end
32
32
 
33
- Thing.send :include, Redef
34
- Thing.new.foo #=> Redef.foo
33
+ Thing.send :include, Extension
34
+ Thing.new.foo #=> Extension.foo
35
35
 
36
- So it will likely become a with/without hell in your code ( you can find dozens of such methods in Rails' code ). And *overridable* is a library that provides a neat mean to resolve this problem.
36
+ But according to the [post][post], this is a bad practice. And *overridable* is a gem that provides a neat mean to resolve this problem.
37
37
 
38
38
  ## How?
39
39
 
@@ -41,17 +41,17 @@ There are two ways to do this with *overridable*: in class or in module.
41
41
 
42
42
  ### In class
43
43
 
44
- Remember Thing and Redef in our first example? Let's make some changes:
44
+ Remember Thing and Extension in our first example? Let's make some changes:
45
45
  require 'overridable'
46
46
 
47
47
  Thing.class_eval {
48
48
  include Overridable
49
49
  overrides :foo
50
50
 
51
- include Redef
51
+ include Extension
52
52
  }
53
53
 
54
- Thing.new.foo #=> Redef.foo
54
+ Thing.new.foo #=> Extension.foo
55
55
  That's it! You can specify which methods can be overrided by `overrides` method. One more example based on the previous one:
56
56
  Thing.class_eval {
57
57
  def bar; 'Thing.bar' end
@@ -61,26 +61,26 @@ That's it! You can specify which methods can be overrided by `overrides` method.
61
61
  overrides :bar, :baz
62
62
  }
63
63
 
64
- Redef.module_eval {
65
- def bar; 'Redef.bar' end
66
- def baz; 'Redef baz' end
67
- def id; 'Redef' end
64
+ Extension.module_eval {
65
+ def bar; 'Extension.bar' end
66
+ def baz; 'Extension baz' end
67
+ def id; 'Extension' end
68
68
  }
69
69
 
70
70
  thing = Thing.new
71
- thing.bar #=> 'Redef.bar'
72
- thing.baz #=> 'Redef.baz'
71
+ thing.bar #=> 'Extension.bar'
72
+ thing.baz #=> 'Extension.baz'
73
73
  thing.id #=> 'Thing'
74
- Of course it's not the end of our story ;) How could I call this *override* if we cannot use `super`? Continue our example:
75
- Redef.module_eval {
74
+ Of course it's not the end of our story ;) How could I call this *override* if we cannot use `super`? Go on with our example:
75
+ Extension.module_eval {
76
76
  def bar
77
77
  parent = super
78
- me = 'Redef.bar'
78
+ me = 'Extension.bar'
79
79
  "I'm #{me} and I overrided #{parent}"
80
80
  end
81
81
  }
82
82
 
83
- Thing.new.bar => I'm Redef.bar and I overrided Thing.bar
83
+ Thing.new.bar => I'm Extension.bar and I overrided Thing.bar
84
84
 
85
85
  ### In module
86
86
 
@@ -92,7 +92,7 @@ If you have many methods in your module and find that it's too annoying to use `
92
92
  def method_n; ... end
93
93
  end
94
94
 
95
- module Redef
95
+ module Extension
96
96
  include Overridable::ModuleMixin
97
97
 
98
98
  def method_one; ... end
@@ -101,7 +101,19 @@ If you have many methods in your module and find that it's too annoying to use `
101
101
  def method_n; ... end
102
102
  end
103
103
 
104
- Thing.send :include, Redef #=> method_one, method_two, ..., method_n are all overrided.
104
+ Thing.send :include, Extension #=> method_one, method_two, ..., method_n are all overrided.
105
+
106
+ Since version 0.3.1, you can use `overrides` in your module to specify which method should be overrided and which should not. Let's rewrite the Extension module above:
107
+ module Extension
108
+ include Overridable::ModuleMixin
109
+ overrides :only => [:method_one, :method_two]
110
+
111
+ # define methods here...
112
+ end
113
+
114
+ Thing.send :include, Extension #=> only method_one and method_two will be overrided.
115
+
116
+ You can also use `overrides :except => [:method_one, :method_two]` to tell the module not to override method_one and method_two in the classes which include it.
105
117
 
106
118
  ## Install
107
119
 
@@ -145,3 +157,5 @@ These features **only** will be added when they are asked for.
145
157
  ## Copyright
146
158
 
147
159
  Copyright (c) 2009 梁智敏. See LICENSE for details.
160
+
161
+ [post]: http://yehudakatz.com/2009/03/06/alias_method_chain-in-models/
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.0
1
+ 0.3.1
data/lib/overridable.rb CHANGED
@@ -90,13 +90,45 @@ module Overridable
90
90
  def append_features mod #:nodoc:
91
91
  # these must be done in `append_features`, not `included`
92
92
  mod.send :include, Overridable
93
- mod.overrides *(
94
- public_instance_methods +
95
- protected_instance_methods +
96
- private_instance_methods
97
- )
93
+
94
+ methods =
95
+ if @override_options && !@override_options[:only].empty?
96
+ @override_options[:only]
97
+ else
98
+ all_methods =
99
+ public_instance_methods +
100
+ protected_instance_methods +
101
+ private_instance_methods
102
+
103
+ if @override_options && !@override_options[:except].empty?
104
+ all_methods - @override_options[:except]
105
+ else
106
+ all_methods
107
+ end
108
+ end
109
+
110
+ mod.overrides *methods
98
111
  super
99
112
  end
113
+
114
+ # Whitelist and blacklist for to-be-overrided methods.
115
+ # If this method with the same options is called multiple times within the same module,
116
+ # only the last call will work.
117
+ # @param [Hash] options the options describe methods are to be or not to be overrided.
118
+ # @option options [Symbol, Array<Symbol>] :only only methods specified in this option will be overrided.
119
+ # @option options [Symbol, Array<Symbol>] :except methods specified in this option will not be overrided.
120
+ # @example
121
+ # overrides :except => [:foo, :bar]
122
+ # overrides :except => :baz
123
+ # overrides :only => [:foo, :bar]
124
+ def overrides options = {}
125
+ raise ArgumentError, "Only :only and :except options are accepted." unless
126
+ options.keys.all? { |k| [:only, :except].include? k }
127
+ @override_options ||= {:only => [], :except => []}
128
+ @override_options[:only] = [options[:only]].flatten.compact if options[:only]
129
+ @override_options[:except] = [options[:except]].flatten.compact if options[:except]
130
+ @override_options[:only] = @override_options[:only] - @override_options[:except]
131
+ end
100
132
  end
101
133
  end
102
134
 
@@ -137,9 +169,9 @@ module Overridable
137
169
  end
138
170
  }
139
171
  $VERBOSE = old_verbose
140
-
141
- nil
142
172
  end
173
+
174
+ nil
143
175
  end
144
176
  end
145
177
 
@@ -9,9 +9,15 @@ context "A module which includes Overridable::ModuleMixin has some methods defin
9
9
  'SomeModule.foo'
10
10
  end
11
11
 
12
+ protected
12
13
  def bar a
13
14
  super + 'SomeModule.bar'
14
15
  end
16
+
17
+ private
18
+ def baz
19
+ super + 'SomeModule.baz'
20
+ end
15
21
  end
16
22
 
17
23
  SomeModule
@@ -24,10 +30,13 @@ context "A module which includes Overridable::ModuleMixin has some methods defin
24
30
  'SomeClass.foo'
25
31
  end
26
32
 
27
- private
28
33
  def bar a
29
34
  'SomeClass.bar'
30
35
  end
36
+
37
+ def baz
38
+ 'SomeClass.baz'
39
+ end
31
40
  end
32
41
 
33
42
  SomeClass
@@ -39,10 +48,80 @@ context "A module which includes Overridable::ModuleMixin has some methods defin
39
48
  asserts("foo should be overrided.") {
40
49
  topic.new.foo
41
50
  }.equals('SomeModule.foo')
51
+
52
+ asserts("bar should be overrided.") {
53
+ topic.new.send :bar, :whatever
54
+ }.equals('SomeClass.bar' + 'SomeModule.bar')
55
+
56
+ asserts("baz should be overrided.") {
57
+ topic.new.send :baz
58
+ }.equals('SomeClass.baz' + 'SomeModule.baz')
59
+ end
60
+
61
+ context "We specify which methods can be overrided." do
62
+ setup {
63
+ SomeModule.module_eval {
64
+ overrides :only => [:foo, :bar]
65
+ }
66
+ topic.send :include, SomeModule
67
+ topic
68
+ }
69
+
70
+ asserts("foo should be overrided.") {
71
+ topic.new.foo
72
+ }.equals('SomeModule.foo')
73
+
74
+ asserts("bar should be overrided.") {
75
+ topic.new.send :bar, :whatever
76
+ }.equals('SomeClass.bar' + 'SomeModule.bar')
77
+
78
+ asserts("baz should not be overrided.") {
79
+ topic.new.baz
80
+ }.equals('SomeClass.baz')
81
+ end
82
+
83
+ context "We specify which methods cannot be overrided." do
84
+ setup {
85
+ SomeModule.module_eval {
86
+ overrides :except => :baz
87
+ }
88
+ topic.send :include, SomeModule
89
+ topic
90
+ }
91
+
92
+ asserts("foo should be overrided.") {
93
+ topic.new.foo
94
+ }.equals('SomeModule.foo')
95
+
96
+ asserts("bar should be overrided.") {
97
+ topic.new.send :bar, :whatever
98
+ }.equals('SomeClass.bar' + 'SomeModule.bar')
99
+
100
+ asserts("baz should not be overrided.") {
101
+ topic.new.baz
102
+ }.equals('SomeClass.baz')
103
+ end
104
+
105
+ context "We specify both the whitelist and blacklist of to-be-overrided methods." do
106
+ setup {
107
+ SomeModule.module_eval {
108
+ overrides :only => [:foo, :bar, :baz], :except => :baz
109
+ }
110
+ topic.send :include, SomeModule
111
+ topic
112
+ }
113
+
114
+ asserts("foo should be overrided.") {
115
+ topic.new.foo
116
+ }.equals('SomeModule.foo')
117
+
42
118
  asserts("bar should be overrided.") {
43
- #topic.new.send :bar, :whatever
44
- topic.new.bar :whatever
119
+ topic.new.send :bar, :whatever
45
120
  }.equals('SomeClass.bar' + 'SomeModule.bar')
121
+
122
+ asserts("baz should not be overrided.") {
123
+ topic.new.baz
124
+ }.equals('SomeClass.baz')
46
125
  end
47
126
  end
48
127
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: overridable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - "\xE6\xA2\x81\xE6\x99\xBA\xE6\x95\x8F(Gimi Liang)"
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-11-24 00:00:00 +08:00
12
+ date: 2009-11-25 00:00:00 +08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency