overridable 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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