dyna_mo 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|