dyna_mo 0.0.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.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +270 -0
- data/Rakefile +10 -0
- data/dyna_mo.gemspec +25 -0
- data/example/for_testing.rb +84 -0
- data/lib/dyna_mo.rb +18 -0
- data/lib/dyna_mo/contexts.rb +42 -0
- data/lib/dyna_mo/environment.rb +66 -0
- data/lib/dyna_mo/module.rb +5 -0
- data/lib/dyna_mo/override_method.rb +42 -0
- data/lib/dyna_mo/version.rb +3 -0
- data/test/helper.rb +16 -0
- data/test/test_basic.rb +89 -0
- data/test/test_contexts.rb +136 -0
- data/test/test_override_method.rb +106 -0
- data/test/test_prepend.rb +69 -0
- metadata +125 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 85938a7bd6853c94b9e45fb70cf3021d36144027
|
4
|
+
data.tar.gz: 9b5de78332444ee32c20d8222d5a1aa37fa9c485
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1aec6e1a6b02f58f13962d31191d2f6b755827cb78a64caa67d8093cac80121fdfc2e04567a3c82baa07af31ab41c16687bc09b6549c45a64a02a9ef3bb18a76
|
7
|
+
data.tar.gz: 7ce62a173331ceadeb40ac5c27772e3f6e199167adb23b0e8758586505ffa86ebd19e46ae1b87bec2b026a63f7bb928b7584c0a7e129327d3da78259663a5438
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 TAGOMORI Satoshi
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,270 @@
|
|
1
|
+
# DynaMo: Testing module to provide dynamic scope method overriding
|
2
|
+
|
3
|
+
Dynamic scope implementation for Method Overriding: override methods by specified context, only in current thread.
|
4
|
+
|
5
|
+
**DON'T USE THIS GEM IN PRODUCTION CODE.**
|
6
|
+
|
7
|
+
## What's this?
|
8
|
+
|
9
|
+
To modify methods' behavior with its dynamic contexts, like this:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
require 'dyna_mo'
|
13
|
+
|
14
|
+
module MyModule
|
15
|
+
class MyClass
|
16
|
+
attr_accessor :num
|
17
|
+
def initialize; @num = 0; end
|
18
|
+
def name; "name"; end
|
19
|
+
def sum(numbers); @num + numbers.reduce(:+); end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
dynamo_define('MyModule::MyClass', :mytest_case_default) do
|
24
|
+
def_method(:initialize) do
|
25
|
+
@num = 1
|
26
|
+
end
|
27
|
+
|
28
|
+
def_method(:name) do
|
29
|
+
"dummyname"
|
30
|
+
end
|
31
|
+
|
32
|
+
def_instance_method(:name, :mytest_case1) do
|
33
|
+
"dummyname1"
|
34
|
+
end
|
35
|
+
|
36
|
+
def_method(:sum) do |numbers|
|
37
|
+
@num + numbers.reduce(:+) + 1
|
38
|
+
end
|
39
|
+
|
40
|
+
def_class_method(:create) do |init_num=0|
|
41
|
+
obj = self.new
|
42
|
+
obj.num = init_num
|
43
|
+
obj
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class SynopsisTest < Test::Unit::TestCase
|
48
|
+
def test_synopsis
|
49
|
+
assert { MyModule::MyClass.new.name == "name" }
|
50
|
+
|
51
|
+
obj = MyModule::MyClass.new
|
52
|
+
|
53
|
+
assert { obj.num == 0 }
|
54
|
+
assert { obj.name == "name" }
|
55
|
+
|
56
|
+
dynamo_context(:mytest_case_default) do
|
57
|
+
assert { obj.num == 0 } # #initialize is not overridden
|
58
|
+
|
59
|
+
assert { obj.name == "dummyname" }
|
60
|
+
assert { MyModule::MyClass.new.name == "dummyname" }
|
61
|
+
|
62
|
+
assert { MyModule::MyClass.new.num == 1 }
|
63
|
+
|
64
|
+
assert { MyModule::MyClass.new.sum([1,2,3]) == (1+(1+2+3)+1) }
|
65
|
+
|
66
|
+
assert { MyModule::MyClass.create(100).num == 100 }
|
67
|
+
end
|
68
|
+
|
69
|
+
dynamo_context(:mytest_case1) do
|
70
|
+
assert { obj.name == "dummyname1" }
|
71
|
+
end
|
72
|
+
|
73
|
+
dynamo_define(MyModule::MyClass, :onetime_context) do
|
74
|
+
def_method(:name) do
|
75
|
+
"onetime"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
dynamo_context(:onetime_context) do
|
80
|
+
assert { obj.name == "onetime" }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
module MyModule; class MyClass2 < MyClass; end; end
|
86
|
+
|
87
|
+
class Synopsis2Test < Test::Unit::TestCase
|
88
|
+
def test_onece_more
|
89
|
+
dynamo_define(MyModule::MyClass, :onetime_context) do
|
90
|
+
def_method(:name) do
|
91
|
+
"onetime"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
dynamo_context(:onetime_context) do
|
96
|
+
assert { MyModule::MyClass2.new.name == "onetime" }
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
```
|
101
|
+
|
102
|
+
## Installation
|
103
|
+
|
104
|
+
Add this line to your application's Gemfile:
|
105
|
+
|
106
|
+
```ruby
|
107
|
+
gem 'dyna_mo'
|
108
|
+
```
|
109
|
+
|
110
|
+
And then execute:
|
111
|
+
|
112
|
+
$ bundle
|
113
|
+
|
114
|
+
Or install it yourself as:
|
115
|
+
|
116
|
+
$ gem install dyna_mo
|
117
|
+
|
118
|
+
## Usage
|
119
|
+
|
120
|
+
Require this module in `helper.rb` or anywhere you want in test code.
|
121
|
+
|
122
|
+
```ruby
|
123
|
+
require "dyna_mo"
|
124
|
+
```
|
125
|
+
|
126
|
+
### Kernel.dynamo_define(name_or_module_instance, default_context_name, &block)
|
127
|
+
|
128
|
+
Create context to define instance methods and class methods of specified Module/Class.
|
129
|
+
|
130
|
+
* `name_or_module_instance` accepts both of String or Module/Class instance. But string specification must be name from top-level, like `Net::HTTP` (or `::Net::HTTP`).
|
131
|
+
|
132
|
+
Given block is evaluated with a receiver instance of `DynaMo::Contexts`.
|
133
|
+
|
134
|
+
```ruby
|
135
|
+
dynamo_define(MyClass, :test_awesome_situation) do
|
136
|
+
# ...
|
137
|
+
end
|
138
|
+
```
|
139
|
+
|
140
|
+
### DynaMo::Contexts#def_instance_method(method_name, context_name = default_context_name, &block)
|
141
|
+
|
142
|
+
Define instance method to override existing instance method, only in specified context. Instance variable reference like `@data` is handled correctly for each objects.
|
143
|
+
|
144
|
+
`super` cannot be used in this block. Use `dynamo_super()` instead.
|
145
|
+
|
146
|
+
Given block is to be method body, and prepended on specified Module/Class, not rewrite method itself. So we can call original method definition by `dynamo_super()`.
|
147
|
+
|
148
|
+
```ruby
|
149
|
+
# in dynamo_define
|
150
|
+
dynamo_instance_method(:data, :my_test_context) do |num|
|
151
|
+
@data * num
|
152
|
+
end
|
153
|
+
obj.instance_eval{ @data = "abc" }
|
154
|
+
obj.data(3) #=> "abcabcabc"
|
155
|
+
```
|
156
|
+
|
157
|
+
The most recently called `#def_instance_method` have highest priority. It's for ad-hoc definition in test code.
|
158
|
+
|
159
|
+
With `def_instance_method`, given block can have arguments of arbitrary number, not same with original definition. But it brings very confusing behavior (especially for `dynamo_super`), so it is not recommended for many cases.
|
160
|
+
|
161
|
+
This method also can add method which does NOT exists in original Module/Class definition.
|
162
|
+
|
163
|
+
### DynaMo::Contexts#def_method(...)
|
164
|
+
|
165
|
+
Alias of `def_instance_method`.
|
166
|
+
|
167
|
+
### DynaMo::Contexts#def_class_method(method_name, context_name = default_context_name, &block)
|
168
|
+
|
169
|
+
Define class method. All other things are same with `define_instance_method`.
|
170
|
+
|
171
|
+
### Kernel.dynamo_context(context_name, &block)
|
172
|
+
|
173
|
+
Create dynamic scope in current thread for specified context name. Given block and lower stack calls run with overridden methods.
|
174
|
+
|
175
|
+
```ruby
|
176
|
+
require "dyna_mo"
|
177
|
+
|
178
|
+
class A1; def self.label; "A"; end; end
|
179
|
+
class A2 < A1; def self.label; (super) * 2; end; end
|
180
|
+
|
181
|
+
dynamo_define(A1, :test) do
|
182
|
+
def_class_method(:label) do
|
183
|
+
"AB"
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
dynamo_context(:test) do
|
188
|
+
A2.label #=> "ABAB"
|
189
|
+
Thread.new { A2.label }.value #=> "AA"
|
190
|
+
end
|
191
|
+
```
|
192
|
+
|
193
|
+
We can apply 2 or more contexts at the same time. If these contexts have definition for same method, the recent defined one is called at first.
|
194
|
+
|
195
|
+
```ruby
|
196
|
+
dynamo_define(A1, :test1) do
|
197
|
+
def_class_method(:label) do
|
198
|
+
"AB"
|
199
|
+
end
|
200
|
+
def_class_method(:label, :test2) do
|
201
|
+
"AC"
|
202
|
+
end
|
203
|
+
def_class_method(:label, :test3) do
|
204
|
+
"BC"
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
dynamo_context(:test2) do
|
209
|
+
dynamo_context(:test3) do
|
210
|
+
dynamo_context(:test1) do
|
211
|
+
A2.label #=> "BC"
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
```
|
216
|
+
|
217
|
+
### Kernel.dynamo_super(*args)
|
218
|
+
|
219
|
+
Use to call original method definition in overriding method body (block). `dyna_mo` method overriding is implemented with `Module.prepend`, so `dynamo_super()` calls original definition, not parent class's definition.
|
220
|
+
|
221
|
+
With `dynamo_super`, all arguments must be specified explicitly.
|
222
|
+
|
223
|
+
```ruby
|
224
|
+
dynamo_define(A1, :test_default) do
|
225
|
+
def_method(:name) do |prefix|
|
226
|
+
prefix + dynamo_super()
|
227
|
+
end
|
228
|
+
end
|
229
|
+
```
|
230
|
+
|
231
|
+
If you use this method with applying multi contexts, `dynamo_super()` calls each overriding method bodies, like this:
|
232
|
+
|
233
|
+
```ruby
|
234
|
+
dynamo_define(A1, :test1) do
|
235
|
+
def_class_method(:label) do
|
236
|
+
"1" + dynamo_super()
|
237
|
+
end
|
238
|
+
def_class_method(:label, :test2) do
|
239
|
+
"2" + dynamo_super()
|
240
|
+
end
|
241
|
+
def_class_method(:label, :test3) do
|
242
|
+
"3" + dynamo_super()
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
dynamo_context(:test1) do
|
247
|
+
dynamo_context(:test2) do
|
248
|
+
dynamo_context(:test3) do
|
249
|
+
# A1.label/test3 -> A1.label/test2 -> A1.label/test1 -> A1.label/(original)
|
250
|
+
A1.label #=> "321A"
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
```
|
255
|
+
|
256
|
+
## Contributing
|
257
|
+
|
258
|
+
1. Fork it ( https://github.com/[my-github-username]/dyna_mo/fork )
|
259
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
260
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
261
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
262
|
+
5. Create a new Pull Request
|
263
|
+
|
264
|
+
## Copyright
|
265
|
+
|
266
|
+
* License
|
267
|
+
* MIT
|
268
|
+
* Author
|
269
|
+
* @tagomoris
|
270
|
+
|
data/Rakefile
ADDED
data/dyna_mo.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'dyna_mo/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "dyna_mo"
|
8
|
+
spec.version = DynaMo::VERSION
|
9
|
+
spec.authors = ["TAGOMORI Satoshi"]
|
10
|
+
spec.email = ["tagomoris@gmail.com"]
|
11
|
+
spec.summary = %q{Testing module to provide dynamic scope method overriding}
|
12
|
+
spec.description = %q{Dynamic scope implementation for Method Overriding: override methods by specified context, only in current thread}
|
13
|
+
spec.homepage = "https://github.com/tagomoris/dyna_mo"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
spec.add_development_dependency "test-unit", "~> 3.0"
|
24
|
+
spec.add_development_dependency "test-unit-power_assert"
|
25
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'dyna_mo'
|
2
|
+
|
3
|
+
module MyModule # External module definition (other's gem)
|
4
|
+
class MyClass
|
5
|
+
attr_accessor :num
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@num = 0
|
9
|
+
end
|
10
|
+
|
11
|
+
def name
|
12
|
+
"name"
|
13
|
+
end
|
14
|
+
|
15
|
+
def sum(numbers)
|
16
|
+
@num + numbers.reduce(:+)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
## use "dynamo_super()" to call super in dynamo overriding
|
22
|
+
|
23
|
+
# in test helper
|
24
|
+
dynamo_define('MyModule::MyClass', default_context = :mytest_case_default) do
|
25
|
+
def_method(:initialize) do # == def_instance_method
|
26
|
+
@num = 1
|
27
|
+
end
|
28
|
+
|
29
|
+
def_method(:name) do # arity == 0, default context
|
30
|
+
"dummyname"
|
31
|
+
end
|
32
|
+
|
33
|
+
def_instance_method(:name, :mytest_case1) do
|
34
|
+
"dummyname1"
|
35
|
+
end
|
36
|
+
|
37
|
+
def_method(:sum) do |numbers|
|
38
|
+
@num + numbers.reduce(:+)
|
39
|
+
end
|
40
|
+
|
41
|
+
# define method only in :mytest_case_default context
|
42
|
+
def_singleton_method(:create) do |init_num=0|
|
43
|
+
obj = self.new
|
44
|
+
obj.num = init_num
|
45
|
+
obj
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# test code
|
50
|
+
class MyTestCase < Test::Unit::TestCase
|
51
|
+
def test_name
|
52
|
+
assert_equal "name", MyModule::MyClass.new.name
|
53
|
+
|
54
|
+
obj = MyModule::MyClass.new
|
55
|
+
|
56
|
+
assert_equal 0, obj.num
|
57
|
+
assert_equal "name", obj.name
|
58
|
+
|
59
|
+
dynamo_context(:mytest_case_default) do
|
60
|
+
assert_equal 0, obj.num # not overridden
|
61
|
+
|
62
|
+
assert_equal "dummyname", obj.name
|
63
|
+
assert_equal "dummyname", MyModule::MyClass.new.name
|
64
|
+
|
65
|
+
assert_equal 1, MyModule::MyClass.new.num
|
66
|
+
|
67
|
+
assert_equal 100, MyModule::MyClass.create(100).num
|
68
|
+
end
|
69
|
+
|
70
|
+
dynamo_context(:mytest_case1) do
|
71
|
+
assert_equal "dummyname1", obj.name
|
72
|
+
end
|
73
|
+
|
74
|
+
dynamo_define(MyModule::MyClass, :onetime_context) do
|
75
|
+
def_method(:name) do
|
76
|
+
"onetime"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
dynamo_context(:onetime_context) do
|
81
|
+
assert_equal "onetime", obj.name
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
data/lib/dyna_mo.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require "dyna_mo/version"
|
2
|
+
|
3
|
+
require "dyna_mo/module"
|
4
|
+
|
5
|
+
module DynaMo
|
6
|
+
# constants or ...
|
7
|
+
end
|
8
|
+
|
9
|
+
require "dyna_mo/contexts"
|
10
|
+
# DynaMo::Contexts
|
11
|
+
# #def_instance_method(method_name, context_name=default_context_name, &block)
|
12
|
+
# #def_singleton_method(method_name, context_name=default_context_name, &block)
|
13
|
+
# #def_method -> #def_instance_method
|
14
|
+
|
15
|
+
require "dyna_mo/environment"
|
16
|
+
# Kernel.dynamo_define(target_name_or_instance, default_context_name_sym, &block)
|
17
|
+
# Kernel.dynamo_context(context_name, &block)
|
18
|
+
# Kernel.dynamo_super(*args)
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require "dyna_mo/override_method"
|
2
|
+
|
3
|
+
module DynaMo
|
4
|
+
class Contexts < BasicObject
|
5
|
+
attr_reader :module_name
|
6
|
+
attr_accessor :default_context_name
|
7
|
+
|
8
|
+
def initialize(mod_name, default_context_name)
|
9
|
+
# mod_name MUST be string here to assure target module_name consistency
|
10
|
+
@module_name = (mod_name =~ /^::/ ? mod_name : '::' + mod_name)
|
11
|
+
@default_context_name = default_context_name.to_sym
|
12
|
+
|
13
|
+
@instance_method_mods = []
|
14
|
+
@class_method_mods = []
|
15
|
+
end
|
16
|
+
|
17
|
+
def __apply__
|
18
|
+
target = ::Kernel.eval(@module_name)
|
19
|
+
|
20
|
+
# reverse: Last defined context's method priority is highest
|
21
|
+
target.prepend( *(@instance_method_mods.reverse.map(&:applied_module)) )
|
22
|
+
(class << target; self; end).prepend( *(@class_method_mods.reverse.map(&:applied_module)) )
|
23
|
+
|
24
|
+
# prepending twice has no effects
|
25
|
+
end
|
26
|
+
|
27
|
+
def def_instance_method(method_name, context_name = @default_context_name, &block)
|
28
|
+
raise "block is not given for def_instance_method" unless block # block_given?
|
29
|
+
|
30
|
+
@instance_method_mods.push OverrideMethod.new(context_name.to_sym, method_name, &block)
|
31
|
+
method_name
|
32
|
+
end
|
33
|
+
alias :def_method :def_instance_method
|
34
|
+
|
35
|
+
def def_class_method(method_name, context_name = @default_context_name, &block)
|
36
|
+
raise "block is not given for def_singleton_method" unless block #_given?
|
37
|
+
|
38
|
+
@class_method_mods.push OverrideMethod.new(context_name.to_sym, method_name, &block)
|
39
|
+
method_name
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require "dyna_mo/contexts"
|
2
|
+
|
3
|
+
module DynaMo
|
4
|
+
module Environment
|
5
|
+
@@contexts_store = {}
|
6
|
+
@@contexts_mutex = Mutex.new
|
7
|
+
|
8
|
+
def self.synchronize
|
9
|
+
@@contexts_mutex.synchronize do
|
10
|
+
yield
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.contexts(name, default_context_name)
|
15
|
+
context = ( @@contexts_store[name] ||= DynaMo::Contexts.new(name, default_context_name) )
|
16
|
+
context.default_context_name = default_context_name
|
17
|
+
context
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.apply_environment
|
21
|
+
@@contexts_store.each do |name, contexts|
|
22
|
+
contexts.__apply__
|
23
|
+
end
|
24
|
+
true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
module Kernel
|
30
|
+
def dynamo_define(target_name_or_instance, default_context_name, &block)
|
31
|
+
raise "block is not given for dynamo_define" unless block_given?
|
32
|
+
# target_name_or_instance accepts module instance, to help programmer to avoid typo
|
33
|
+
target = target_name_or_instance.is_a?(Module) ? target_name_or_instance.name : target_name_or_instance.to_s
|
34
|
+
::DynaMo::Environment.synchronize do
|
35
|
+
# get/create context object and evaluate block with it
|
36
|
+
context = ::DynaMo::Environment.contexts(target, default_context_name)
|
37
|
+
context.instance_exec(&block)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def dynamo_context(context_name, &block)
|
42
|
+
raise "block is not given for dynamo_context" unless block_given?
|
43
|
+
# get context, apply context and yield block
|
44
|
+
::DynaMo::Environment.synchronize do
|
45
|
+
::DynaMo::Environment.apply_environment
|
46
|
+
end
|
47
|
+
Thread.current[:dynamo_contexts] ||= {}
|
48
|
+
Thread.current[:dynamo_contexts][context_name] = true
|
49
|
+
begin
|
50
|
+
yield
|
51
|
+
ensure
|
52
|
+
Thread.current[:dynamo_contexts].delete(context_name)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def dynamo_super(*args)
|
57
|
+
Thread.current[:dynamo_stack].last.call(*args)
|
58
|
+
end
|
59
|
+
|
60
|
+
## This method is to call `super` just like in original definition,
|
61
|
+
## without calls of any other contexts' definition and original method definition
|
62
|
+
# def dynamo_ultra_super(*args)
|
63
|
+
# # But, we need Method#super_method and something to get Method object now running...
|
64
|
+
# raise NotImplementedError, "We need Kernel.current_method"
|
65
|
+
# end
|
66
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module DynaMo
|
2
|
+
class OverrideMethod
|
3
|
+
attr_reader :context, :name
|
4
|
+
|
5
|
+
def initialize(context, name, &block)
|
6
|
+
@context = context.to_sym
|
7
|
+
@name = name.to_sym
|
8
|
+
@override = block
|
9
|
+
|
10
|
+
@mod = nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def applied_module
|
14
|
+
return @mod if @mod
|
15
|
+
|
16
|
+
mod = Module.new
|
17
|
+
mod.__send__(:define_method, @name, self.to_proc)
|
18
|
+
@mod = mod
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_proc
|
22
|
+
context = @context
|
23
|
+
override = @override
|
24
|
+
|
25
|
+
-> (*args) {
|
26
|
+
Thread.current[:dynamo_contexts] ||= {}
|
27
|
+
Thread.current[:dynamo_stack] ||= []
|
28
|
+
|
29
|
+
if Thread.current[:dynamo_contexts][context]
|
30
|
+
Thread.current[:dynamo_stack].push(-> (*args) { super(*args) })
|
31
|
+
begin
|
32
|
+
instance_exec(*args, &override)
|
33
|
+
ensure
|
34
|
+
Thread.current[:dynamo_stack].pop
|
35
|
+
end
|
36
|
+
else
|
37
|
+
super(*args)
|
38
|
+
end
|
39
|
+
}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'test/unit/power_assert'
|
3
|
+
|
4
|
+
def virtual_dynamo_context(name)
|
5
|
+
Thread.current[:dynamo_contexts] ||= {}
|
6
|
+
Thread.current[:dynamo_contexts][name] = true
|
7
|
+
begin
|
8
|
+
yield
|
9
|
+
ensure
|
10
|
+
Thread.current[:dynamo_contexts].delete(name)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def virtual_dynamo_super(*args)
|
15
|
+
Thread.current[:dynamo_stack].last.call(*args)
|
16
|
+
end
|
data/test/test_basic.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'dyna_mo'
|
3
|
+
|
4
|
+
module MyModule
|
5
|
+
class MyClass
|
6
|
+
attr_accessor :num
|
7
|
+
def initialize; @num = 0; end
|
8
|
+
def name; "name"; end
|
9
|
+
def sum(numbers); @num + numbers.reduce(:+); end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
dynamo_define('MyModule::MyClass', :mytest_case_default) do
|
14
|
+
def_method(:initialize) do
|
15
|
+
@num = 1
|
16
|
+
end
|
17
|
+
|
18
|
+
def_method(:name) do
|
19
|
+
"dummyname"
|
20
|
+
end
|
21
|
+
|
22
|
+
def_instance_method(:name, :mytest_case1) do
|
23
|
+
"dummyname1"
|
24
|
+
end
|
25
|
+
|
26
|
+
def_method(:sum) do |numbers|
|
27
|
+
@num + numbers.reduce(:+) + 1
|
28
|
+
end
|
29
|
+
|
30
|
+
def_class_method(:create) do |init_num=0|
|
31
|
+
obj = self.new
|
32
|
+
obj.num = init_num
|
33
|
+
obj
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class SynopsisTest < Test::Unit::TestCase
|
38
|
+
def test_synopsis
|
39
|
+
assert { MyModule::MyClass.new.name == "name" }
|
40
|
+
|
41
|
+
obj = MyModule::MyClass.new
|
42
|
+
|
43
|
+
assert { obj.num == 0 }
|
44
|
+
assert { obj.name == "name" }
|
45
|
+
|
46
|
+
dynamo_context(:mytest_case_default) do
|
47
|
+
assert { obj.num == 0 } # #initialize is not overridden
|
48
|
+
|
49
|
+
assert { obj.name == "dummyname" }
|
50
|
+
assert { MyModule::MyClass.new.name == "dummyname" }
|
51
|
+
|
52
|
+
assert { MyModule::MyClass.new.num == 1 }
|
53
|
+
|
54
|
+
assert { MyModule::MyClass.new.sum([1,2,3]) == (1+(1+2+3)+1) }
|
55
|
+
|
56
|
+
assert { MyModule::MyClass.create(100).num == 100 }
|
57
|
+
end
|
58
|
+
|
59
|
+
dynamo_context(:mytest_case1) do
|
60
|
+
assert { obj.name == "dummyname1" }
|
61
|
+
end
|
62
|
+
|
63
|
+
dynamo_define(MyModule::MyClass, :onetime_context) do
|
64
|
+
def_method(:name) do
|
65
|
+
"onetime"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
dynamo_context(:onetime_context) do
|
70
|
+
assert { obj.name == "onetime" }
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
module MyModule; class MyClass2 < MyClass; end; end
|
76
|
+
|
77
|
+
class Synopsis2Test < Test::Unit::TestCase
|
78
|
+
def test_onece_more
|
79
|
+
dynamo_define(MyModule::MyClass, :onetime_context) do
|
80
|
+
def_method(:name) do
|
81
|
+
"onetime"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
dynamo_context(:onetime_context) do
|
86
|
+
assert { MyModule::MyClass2.new.name == "onetime" }
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'dyna_mo/contexts'
|
3
|
+
|
4
|
+
module Foo
|
5
|
+
class Bar
|
6
|
+
def self.label
|
7
|
+
"baz"
|
8
|
+
end
|
9
|
+
def text
|
10
|
+
"foobar"
|
11
|
+
end
|
12
|
+
def concat(a, b, separator=".")
|
13
|
+
a + separator + b
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class Baz < Bar
|
18
|
+
def text
|
19
|
+
(super) + "baz"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class ContextsTest < Test::Unit::TestCase
|
25
|
+
def test_instance_method_contexts
|
26
|
+
cxt = DynaMo::Contexts.new('Foo::Bar', :test_i0)
|
27
|
+
cxt.def_instance_method(:text) do # default context name
|
28
|
+
"foobar0"
|
29
|
+
end
|
30
|
+
cxt.def_instance_method(:text, :test_i1) do
|
31
|
+
"foobar1"
|
32
|
+
end
|
33
|
+
cxt.def_instance_method(:text, :test_i2) do |x| # special argument for test
|
34
|
+
"foobar2:" + x
|
35
|
+
end
|
36
|
+
|
37
|
+
cxt.__apply__
|
38
|
+
|
39
|
+
assert { Foo::Bar.new.text == "foobar" }
|
40
|
+
virtual_dynamo_context(:test_i0) do
|
41
|
+
assert { Foo::Bar.new.text == "foobar0" }
|
42
|
+
end
|
43
|
+
virtual_dynamo_context(:test_i1) do
|
44
|
+
assert { Foo::Bar.new.text == "foobar1" }
|
45
|
+
end
|
46
|
+
virtual_dynamo_context(:test_i2) do
|
47
|
+
assert { Foo::Bar.new.text("z") == "foobar2:z" }
|
48
|
+
end
|
49
|
+
|
50
|
+
cxt.def_method(:text, :test_i0) do
|
51
|
+
"foobar_zero"
|
52
|
+
end
|
53
|
+
|
54
|
+
cxt.__apply__
|
55
|
+
|
56
|
+
assert { Foo::Bar.new.text == "foobar" }
|
57
|
+
virtual_dynamo_context(:test_i0) do
|
58
|
+
assert { Foo::Bar.new.text == "foobar_zero" }
|
59
|
+
end
|
60
|
+
virtual_dynamo_context(:test_i1) do
|
61
|
+
assert { Foo::Bar.new.text == "foobar1" }
|
62
|
+
end
|
63
|
+
virtual_dynamo_context(:test_i2) do
|
64
|
+
assert { Foo::Bar.new.text("z") == "foobar2:z" }
|
65
|
+
end
|
66
|
+
|
67
|
+
# 2 or more dynamo contexts work well: last defined method is prior
|
68
|
+
virtual_dynamo_context(:test_i0) do
|
69
|
+
virtual_dynamo_context(:test_i1) do
|
70
|
+
assert { Foo::Bar.new.text == "foobar_zero" }
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_for_subclass
|
76
|
+
cxt1 = DynaMo::Contexts.new('Foo::Bar', :test_s0)
|
77
|
+
cxt1.def_instance_method(:text, :test_s1) do
|
78
|
+
"foobar1"
|
79
|
+
end
|
80
|
+
cxt1.def_instance_method(:text) do # default context name
|
81
|
+
"foobar0"
|
82
|
+
end
|
83
|
+
# test_s0 is prior for Foo::Bar
|
84
|
+
|
85
|
+
cxt1.__apply__
|
86
|
+
|
87
|
+
# subclass methods are prior, and prepended methods, original methods
|
88
|
+
assert { Foo::Baz.new.text == "foobarbaz" }
|
89
|
+
virtual_dynamo_context(:test_s0) do
|
90
|
+
assert { Foo::Baz.new.text == "foobar0baz" }
|
91
|
+
end
|
92
|
+
virtual_dynamo_context(:test_s1) do
|
93
|
+
assert { Foo::Baz.new.text == "foobar1baz" }
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_multi_context_and_threads
|
98
|
+
cxt1 = DynaMo::Contexts.new('Foo::Bar', :test_m0)
|
99
|
+
cxt1.def_instance_method(:text, :test_m1) do
|
100
|
+
"foobar1"
|
101
|
+
end
|
102
|
+
cxt1.def_instance_method(:text) do # default context name
|
103
|
+
"foobar0"
|
104
|
+
end
|
105
|
+
# test_m0 is prior for Foo::Bar
|
106
|
+
|
107
|
+
cxt1.__apply__
|
108
|
+
|
109
|
+
cxt2 = DynaMo::Contexts.new('Foo::Baz', :test_m0)
|
110
|
+
cxt2.def_method(:text) do
|
111
|
+
virtual_dynamo_super() + " baz0"
|
112
|
+
end
|
113
|
+
cxt2.def_method(:text, :test_m1) do
|
114
|
+
virtual_dynamo_super() + " baz1"
|
115
|
+
end
|
116
|
+
# test_m1 is prior for Foo:Baz
|
117
|
+
|
118
|
+
cxt2.__apply__
|
119
|
+
|
120
|
+
virtual_dynamo_context(:test_m0) do
|
121
|
+
virtual_dynamo_context(:test_m1) do
|
122
|
+
# Baz/test_m1 -> Baz/test_m0 -> Baz/origin -> Bar/test_m0
|
123
|
+
assert { Foo::Baz.new.text == "foobar0baz baz0 baz1" }
|
124
|
+
|
125
|
+
# Other thread does NOT accept any effects
|
126
|
+
val1 = Thread.new { Foo::Baz.new.text }.value
|
127
|
+
assert { val1 == "foobarbaz" }
|
128
|
+
|
129
|
+
# Other thread can apply other context
|
130
|
+
# Baz/test_m1 -> Baz/origin -> Bar/test_m1 (without test_m0)
|
131
|
+
val2 = Thread.new { virtual_dynamo_context(:test_m1) { Foo::Baz.new.text } }.value
|
132
|
+
assert { val2 == "foobar1baz baz1" }
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require "helper"
|
2
|
+
require "dyna_mo/override_method"
|
3
|
+
|
4
|
+
class Target1
|
5
|
+
def self.label
|
6
|
+
"target1"
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@n = 1
|
11
|
+
end
|
12
|
+
|
13
|
+
def name
|
14
|
+
"target#{@n}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class Target2 < Target1
|
19
|
+
def self.label
|
20
|
+
super
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize
|
24
|
+
@n = 2
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class OverrideMethodTest < Test::Unit::TestCase
|
29
|
+
def test_applied_module_returns_unique_instance
|
30
|
+
m1 = DynaMo::OverrideMethod.new(:test_applied_module, :foo) do
|
31
|
+
"foo"
|
32
|
+
end
|
33
|
+
obj1 = m1.applied_module
|
34
|
+
assert { obj1.object_id == m1.applied_module.object_id }
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_instance_methods
|
38
|
+
t1 = Target1.new
|
39
|
+
assert { t1.name == "target1" }
|
40
|
+
|
41
|
+
m1 = DynaMo::OverrideMethod.new(:test_instance_methods, :name) do
|
42
|
+
"p#{@n}:" + virtual_dynamo_super()
|
43
|
+
end
|
44
|
+
|
45
|
+
Target1.send(:prepend, m1.applied_module)
|
46
|
+
|
47
|
+
assert { t1.name == "target1" }
|
48
|
+
virtual_dynamo_context(:test_instance_methods) do
|
49
|
+
assert { t1.name == "p1:target1" }
|
50
|
+
end
|
51
|
+
assert { t1.name == "target1" }
|
52
|
+
|
53
|
+
m2 = DynaMo::OverrideMethod.new(:test_instance_methods, :initialize) do
|
54
|
+
@n = 1111
|
55
|
+
end
|
56
|
+
Target2.prepend(m2.applied_module)
|
57
|
+
t2 = Target2.new
|
58
|
+
|
59
|
+
assert { t1.name == "target1" }
|
60
|
+
virtual_dynamo_context(:test_instance_methods) do
|
61
|
+
assert { t1.name == "p1:target1" }
|
62
|
+
assert { t2.name == "p2:target2" }
|
63
|
+
end
|
64
|
+
assert { t1.name == "target1" }
|
65
|
+
|
66
|
+
virtual_dynamo_context(:test_instance_methods) do
|
67
|
+
assert { Target1.new.name == "p1:target1" }
|
68
|
+
assert { Target2.new.name == "p1111:target1111" }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_class_methods
|
73
|
+
assert { Target1.label == "target1" }
|
74
|
+
|
75
|
+
m1 = DynaMo::OverrideMethod.new(:test_class_methods, :label) do
|
76
|
+
"p1:target1"
|
77
|
+
end
|
78
|
+
|
79
|
+
mod1 = m1.applied_module
|
80
|
+
(class << Target1; self; end).send(:prepend, mod1)
|
81
|
+
|
82
|
+
assert { Target1.label == "target1" }
|
83
|
+
virtual_dynamo_context(:test_class_methods) do
|
84
|
+
assert { Target1.label == "p1:target1" }
|
85
|
+
end
|
86
|
+
assert { Target1.label == "target1" }
|
87
|
+
|
88
|
+
# Target2.label is equal to Target1.self
|
89
|
+
assert { Target2.label == "target1" }
|
90
|
+
virtual_dynamo_context(:test_class_methods) do
|
91
|
+
assert { Target2.label == "p1:target1" }
|
92
|
+
end
|
93
|
+
assert { Target2.label == "target1" }
|
94
|
+
|
95
|
+
m2 = DynaMo::OverrideMethod.new(:test_class_methods, :label) do
|
96
|
+
virtual_dynamo_super().gsub(/1/, '2')
|
97
|
+
end
|
98
|
+
(class << Target2; self; end).send(:prepend, m2.applied_module)
|
99
|
+
|
100
|
+
assert { Target2.label == "target1" }
|
101
|
+
virtual_dynamo_context(:test_class_methods) do
|
102
|
+
assert { Target2.label == "p2:target2" }
|
103
|
+
end
|
104
|
+
assert { Target2.label == "target1" }
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'dyna_mo/module'
|
3
|
+
|
4
|
+
class ModulePrependTest < Test::Unit::TestCase
|
5
|
+
module P1
|
6
|
+
def name
|
7
|
+
val = super
|
8
|
+
"p1:" + val
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module P2
|
13
|
+
def name
|
14
|
+
val = super
|
15
|
+
"p2:" + val
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class X
|
20
|
+
def name
|
21
|
+
"x"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Y < X
|
26
|
+
def name
|
27
|
+
"y"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_base
|
32
|
+
assert { X.new.name == "x" }
|
33
|
+
assert { Y.new.name == "y" }
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_normal_prepend
|
37
|
+
X.send(:prepend, P1)
|
38
|
+
|
39
|
+
assert { X.new.name == "p1:x" }
|
40
|
+
assert X.include?(P1)
|
41
|
+
assert X.prepend?(P1)
|
42
|
+
|
43
|
+
assert { Y.new.name == "y" } # not prepend
|
44
|
+
assert Y.include?(P1)
|
45
|
+
assert (not Y.prepend?(P1))
|
46
|
+
|
47
|
+
Y.send(:prepend, P2)
|
48
|
+
|
49
|
+
assert { Y.new.name == "p2:y" }
|
50
|
+
assert Y.include?(P2)
|
51
|
+
assert Y.prepend?(P2)
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_prepend_duplicated_module
|
55
|
+
assert X.prepend?(P1)
|
56
|
+
assert (not Y.prepend?(P1))
|
57
|
+
assert Y.prepend?(P2)
|
58
|
+
|
59
|
+
assert { Y.new.name == "p2:y" }
|
60
|
+
dup_mod = P1.dup
|
61
|
+
|
62
|
+
Y.send(:prepend, dup_mod)
|
63
|
+
|
64
|
+
assert Y.prepend?(dup_mod)
|
65
|
+
assert { Y.new.name == "p1:p2:y" }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
|
metadata
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dyna_mo
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- TAGOMORI Satoshi
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-10-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: test-unit
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: test-unit-power_assert
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: 'Dynamic scope implementation for Method Overriding: override methods
|
70
|
+
by specified context, only in current thread'
|
71
|
+
email:
|
72
|
+
- tagomoris@gmail.com
|
73
|
+
executables: []
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- ".gitignore"
|
78
|
+
- Gemfile
|
79
|
+
- LICENSE.txt
|
80
|
+
- README.md
|
81
|
+
- Rakefile
|
82
|
+
- dyna_mo.gemspec
|
83
|
+
- example/for_testing.rb
|
84
|
+
- lib/dyna_mo.rb
|
85
|
+
- lib/dyna_mo/contexts.rb
|
86
|
+
- lib/dyna_mo/environment.rb
|
87
|
+
- lib/dyna_mo/module.rb
|
88
|
+
- lib/dyna_mo/override_method.rb
|
89
|
+
- lib/dyna_mo/version.rb
|
90
|
+
- test/helper.rb
|
91
|
+
- test/test_basic.rb
|
92
|
+
- test/test_contexts.rb
|
93
|
+
- test/test_override_method.rb
|
94
|
+
- test/test_prepend.rb
|
95
|
+
homepage: https://github.com/tagomoris/dyna_mo
|
96
|
+
licenses:
|
97
|
+
- MIT
|
98
|
+
metadata: {}
|
99
|
+
post_install_message:
|
100
|
+
rdoc_options: []
|
101
|
+
require_paths:
|
102
|
+
- lib
|
103
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- - ">="
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: '0'
|
108
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
109
|
+
requirements:
|
110
|
+
- - ">="
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0'
|
113
|
+
requirements: []
|
114
|
+
rubyforge_project:
|
115
|
+
rubygems_version: 2.2.2
|
116
|
+
signing_key:
|
117
|
+
specification_version: 4
|
118
|
+
summary: Testing module to provide dynamic scope method overriding
|
119
|
+
test_files:
|
120
|
+
- test/helper.rb
|
121
|
+
- test/test_basic.rb
|
122
|
+
- test/test_contexts.rb
|
123
|
+
- test/test_override_method.rb
|
124
|
+
- test/test_prepend.rb
|
125
|
+
has_rdoc:
|