bunraku 3.0.0
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/Manifest.txt +39 -0
- data/README.txt +25 -0
- data/Rakefile +93 -0
- data/examples/corechain.rb +46 -0
- data/examples/person.rb +67 -0
- data/examples/person2.rb +62 -0
- data/examples/person3.rb +72 -0
- data/examples/rentalshop.rb +127 -0
- data/examples/requires.rb +50 -0
- data/examples/scope.rb +63 -0
- data/hacks/add_method_by_method_of_Class.rb +18 -0
- data/hacks/add_method_to_Class.rb +12 -0
- data/hacks/add_method_with_local_context.rb +27 -0
- data/hacks/anonymous_method.rb +37 -0
- data/hacks/class_creation_events.rb +45 -0
- data/hacks/get_nested_class.rb +22 -0
- data/hacks/hook_method.rb +50 -0
- data/hacks/method_missing_chain.rb +33 -0
- data/hacks/method_missing_chain_override.rb +39 -0
- data/hacks/pluralize.rb +24 -0
- data/lib/bunraku.rb +3 -0
- data/lib/bunraku/base.rb +9 -0
- data/lib/bunraku/class_ext.rb +37 -0
- data/lib/bunraku/core.rb +257 -0
- data/lib/bunraku/exceptions.rb +10 -0
- data/lib/bunraku/proxies.rb +121 -0
- data/lib/bunraku/utils.rb +21 -0
- data/lib/bunraku/version.rb +9 -0
- data/scripts/makemanifest.rb +20 -0
- data/scripts/uproadwebsite.sh +18 -0
- data/setup.rb +1585 -0
- data/spec/def_context_spec.rb +34 -0
- data/spec/interaction_spec.rb +127 -0
- data/spec/require_spec.rb +44 -0
- data/spec/role2_spec.rb +116 -0
- data/spec/role_spec.rb +120 -0
- data/test/test_bunraku.rb +11 -0
- data/test/test_helper.rb +2 -0
- data/website/index.html +13 -0
- metadata +94 -0
@@ -0,0 +1,37 @@
|
|
1
|
+
class Module
|
2
|
+
def context(name, &block)
|
3
|
+
if const_defined?(name)
|
4
|
+
context_class = const_get(name)
|
5
|
+
else
|
6
|
+
context_class = Class.new
|
7
|
+
const_set(name, context_class)
|
8
|
+
context_class.module_eval do
|
9
|
+
include Bunraku::Context
|
10
|
+
end
|
11
|
+
def context_class.role(name, &block)
|
12
|
+
if const_defined?(name)
|
13
|
+
role_class = const_get(name)
|
14
|
+
else
|
15
|
+
role_class = Class.new
|
16
|
+
const_set(name, role_class)
|
17
|
+
role_class.module_eval do
|
18
|
+
include Bunraku::Role
|
19
|
+
extend Bunraku::RoleExtensions
|
20
|
+
end
|
21
|
+
end
|
22
|
+
role_class.module_eval(&block)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
context_class.module_eval(&block)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class Class
|
30
|
+
def as_context
|
31
|
+
include Bunraku::Context
|
32
|
+
end
|
33
|
+
def as_role
|
34
|
+
include Bunraku::Role
|
35
|
+
extend Bunraku::RoleExtensions
|
36
|
+
end
|
37
|
+
end
|
data/lib/bunraku/core.rb
ADDED
@@ -0,0 +1,257 @@
|
|
1
|
+
|
2
|
+
=begin
|
3
|
+
Interfaces for external objects
|
4
|
+
=end
|
5
|
+
module Bunraku
|
6
|
+
module Context
|
7
|
+
def bind(&spec_block)
|
8
|
+
BindExecuter.new(self, spec_block)
|
9
|
+
end
|
10
|
+
def unbind
|
11
|
+
context = self
|
12
|
+
self.class.constants.each do |const_name|
|
13
|
+
role_list = Utils.get_role_list(context, const_name)
|
14
|
+
next unless role_list
|
15
|
+
role_list.delete_if do |role_holder|
|
16
|
+
role_holder.unbind
|
17
|
+
true
|
18
|
+
end
|
19
|
+
end
|
20
|
+
nil
|
21
|
+
end
|
22
|
+
private
|
23
|
+
def method_missing(name, *args)
|
24
|
+
role_class = Utils.get_role_class(self, name)
|
25
|
+
return super(name, *args) unless role_class
|
26
|
+
role_list_name = Utils.role_list_name(name)
|
27
|
+
unless instance_variables.include? role_list_name
|
28
|
+
instance_variable_set(role_list_name, [])
|
29
|
+
end
|
30
|
+
role_list = instance_variable_get(role_list_name)
|
31
|
+
return RoleBinder.new(self, role_list, role_class)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
module Role
|
36
|
+
protected
|
37
|
+
def context
|
38
|
+
ContextProxy.new(@role_holder.context)
|
39
|
+
end
|
40
|
+
def core
|
41
|
+
@role_holder.core
|
42
|
+
end
|
43
|
+
private
|
44
|
+
def set_role_holder(role_holder)
|
45
|
+
@role_holder = role_holder
|
46
|
+
end
|
47
|
+
def method_missing(name, *args)
|
48
|
+
m = @role_holder.get_super_method(name.to_sym)
|
49
|
+
return m.call(*args) if m
|
50
|
+
super(name, *args)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class RoleBinder
|
55
|
+
def initialize(context, role_list, role_class)
|
56
|
+
@context = context
|
57
|
+
@role_list = role_list
|
58
|
+
@role_class = role_class
|
59
|
+
end
|
60
|
+
def bind(obj, &block)
|
61
|
+
role_holder = @role_list.detect do |role_holder|
|
62
|
+
role_holder.target == obj
|
63
|
+
end
|
64
|
+
unless role_holder
|
65
|
+
role = @role_class.new
|
66
|
+
role_holder = RoleHolder.new(@context, role, obj)
|
67
|
+
role_holder.bind
|
68
|
+
@role_list << role_holder
|
69
|
+
end
|
70
|
+
block.call(role_holder) if block
|
71
|
+
@role_class.requires_test(role_holder)
|
72
|
+
nil
|
73
|
+
end
|
74
|
+
def unbind(obj)
|
75
|
+
@role_list.delete_if do |role_holder|
|
76
|
+
if role_holder.target == obj
|
77
|
+
role_holder.unbind
|
78
|
+
true
|
79
|
+
else
|
80
|
+
false
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
class RoleHolder
|
87
|
+
CORE_GETTER = :__bunraku_core_get
|
88
|
+
def initialize(context, role, target)
|
89
|
+
@context = context
|
90
|
+
@role = role
|
91
|
+
@target = target
|
92
|
+
@target_mod = Module.new
|
93
|
+
@target.extend(@target_mod)
|
94
|
+
@methods = {}
|
95
|
+
@core_getter = nil
|
96
|
+
end
|
97
|
+
attr :context
|
98
|
+
attr :role
|
99
|
+
attr :target
|
100
|
+
|
101
|
+
def replace_to(role_method_name, target_method_name)
|
102
|
+
@methods[role_method_name.to_sym] = @target.method(target_method_name)
|
103
|
+
end
|
104
|
+
|
105
|
+
def def_method(name, &body)
|
106
|
+
tmpname = "__temp__" + name.to_s
|
107
|
+
@target_mod.instance_eval do
|
108
|
+
public
|
109
|
+
define_method(tmpname, &body)
|
110
|
+
end
|
111
|
+
@methods[name] = @target.method(tmpname)
|
112
|
+
@target_mod.instance_eval do
|
113
|
+
undef_method(tmpname)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def get_method(name)
|
118
|
+
name = name.to_sym
|
119
|
+
return @role.method(name) if @role.methods.include?(name.to_s)
|
120
|
+
return @methods[name] if @methods[name]
|
121
|
+
return @target.method(name) if @target.methods.include?(name.to_s)
|
122
|
+
nil
|
123
|
+
end
|
124
|
+
|
125
|
+
def get_super_method(name)
|
126
|
+
name = name.to_sym
|
127
|
+
return @methods[name] if @methods[name]
|
128
|
+
return @target.method(name) if @target.methods.include?(name.to_s)
|
129
|
+
#return @role.method(name) if @role.methods.include?(name.to_s)
|
130
|
+
nil
|
131
|
+
end
|
132
|
+
|
133
|
+
def core
|
134
|
+
return CoreProxy.new(self) if @core_getter == nil
|
135
|
+
core_holder = @core_getter.call()
|
136
|
+
if core_holder != nil
|
137
|
+
return HolderProxy.new(core_holder)
|
138
|
+
else
|
139
|
+
return CoreProxy.new(self)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def get_core
|
144
|
+
proc do
|
145
|
+
return self if @target != nil
|
146
|
+
return nil if @core_getter == nil
|
147
|
+
return @core_getter.call()
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def bind
|
152
|
+
role_holder = self
|
153
|
+
@role.instance_eval do
|
154
|
+
set_role_holder(role_holder)
|
155
|
+
end
|
156
|
+
begin
|
157
|
+
@core_getter = @target.instance_eval do
|
158
|
+
send(CORE_GETTER)
|
159
|
+
end
|
160
|
+
rescue
|
161
|
+
end
|
162
|
+
@target_mod.instance_eval do
|
163
|
+
private
|
164
|
+
define_method(CORE_GETTER) do
|
165
|
+
role_holder.get_core
|
166
|
+
end
|
167
|
+
define_method(:method_missing) do |name, *args|
|
168
|
+
m = role_holder.get_method(name.to_sym)
|
169
|
+
return m.call(*args) if m
|
170
|
+
super(name, *args)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
# override processing
|
174
|
+
@role.class.each_overrides do |method|
|
175
|
+
@methods[method] = @target.method(method)
|
176
|
+
@target_mod.instance_eval do
|
177
|
+
define_method(method) do |*args|
|
178
|
+
m = role_holder.get_method(method)
|
179
|
+
return m.call(*args) if m
|
180
|
+
super(*args)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
@role.init_role if @role.methods.include?("init_role")
|
186
|
+
end
|
187
|
+
|
188
|
+
def unbind
|
189
|
+
@target_mod.instance_eval do
|
190
|
+
private
|
191
|
+
define_method(CORE_GETTER) do
|
192
|
+
super()
|
193
|
+
end
|
194
|
+
define_method(:method_missing) do |name, *args|
|
195
|
+
super(name, *args)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
@target = nil
|
199
|
+
@methods = {}
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
module RoleExtensions
|
204
|
+
def requires(&block)
|
205
|
+
@requires = [] unless instance_variables.include? "@requires"
|
206
|
+
@requires << block
|
207
|
+
end
|
208
|
+
|
209
|
+
def override(method)
|
210
|
+
@overrides = [] unless instance_variables.include? "@overrides"
|
211
|
+
@overrides << method.to_sym
|
212
|
+
end
|
213
|
+
|
214
|
+
def requires_test(holder)
|
215
|
+
return true unless instance_variables.include? "@requires"
|
216
|
+
req = RoleRequires.new(holder)
|
217
|
+
@requires.each do |block|
|
218
|
+
block.call(req)
|
219
|
+
end
|
220
|
+
raise BindRoleError.new(req.errors) unless req.errors.empty?
|
221
|
+
end
|
222
|
+
|
223
|
+
def each_overrides(&block)
|
224
|
+
@overrides.each(&block) if instance_variables.include? "@overrides"
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
class RoleRequires
|
229
|
+
def initialize(holder)
|
230
|
+
@holder = holder
|
231
|
+
@errors = []
|
232
|
+
end
|
233
|
+
attr :errors
|
234
|
+
|
235
|
+
def method?(name)
|
236
|
+
unless @holder.get_method(name.to_sym)
|
237
|
+
@errors << "require method: #{name.to_s}"
|
238
|
+
end
|
239
|
+
nil
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
class BindExecuter
|
244
|
+
def initialize(context, spec)
|
245
|
+
@context = context
|
246
|
+
@spec = spec
|
247
|
+
end
|
248
|
+
def call(&block)
|
249
|
+
context = @context
|
250
|
+
@spec.call(context)
|
251
|
+
result = block.call()
|
252
|
+
context.unbind
|
253
|
+
result
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
@@ -0,0 +1,121 @@
|
|
1
|
+
|
2
|
+
=begin
|
3
|
+
Proxies are objects for using only inside role methods.
|
4
|
+
=end
|
5
|
+
module Bunraku
|
6
|
+
class ContextProxy
|
7
|
+
def initialize(context)
|
8
|
+
@context = context
|
9
|
+
end
|
10
|
+
|
11
|
+
def method_missing(name, *args)
|
12
|
+
if @context.class.constants.include?(name.to_s)
|
13
|
+
role = @context.class.const_get(name)
|
14
|
+
return RoleProxy.new(@context, name, role)
|
15
|
+
end
|
16
|
+
sname = name.to_s.singularize.to_sym
|
17
|
+
if @context.class.constants.include?(sname.to_s)
|
18
|
+
role = @context.class.const_get(sname)
|
19
|
+
default = if args.size == 1 then args[0] else nil end
|
20
|
+
return RolesProxy.new(@context, sname, role, default) if role
|
21
|
+
end
|
22
|
+
if @context.methods.include?(name.to_s)
|
23
|
+
return @context.send(name, *args)
|
24
|
+
end
|
25
|
+
super(name, *args)
|
26
|
+
end
|
27
|
+
|
28
|
+
def eql?(o)
|
29
|
+
return false if o.class != self.class
|
30
|
+
@context == o.instance_variable_get(:@context)
|
31
|
+
end
|
32
|
+
def hash
|
33
|
+
@context.hash
|
34
|
+
end
|
35
|
+
def ==(o)
|
36
|
+
eql?(o)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class CoreProxy
|
41
|
+
def initialize(role_holder)
|
42
|
+
@role_holder = role_holder
|
43
|
+
end
|
44
|
+
private
|
45
|
+
def method_missing(name, *args)
|
46
|
+
m = @role_holder.get_super_method(name)
|
47
|
+
return m.call(*args) if m
|
48
|
+
super(name, *args)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class HolderProxy
|
53
|
+
def initialize(role_holder)
|
54
|
+
@role_holder = role_holder
|
55
|
+
end
|
56
|
+
private
|
57
|
+
def method_missing(name, *args)
|
58
|
+
m = @role_holder.get_method(name)
|
59
|
+
return m.call(*args) if m
|
60
|
+
super(name, *args)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class RoleProxyBase
|
65
|
+
def initialize(context, role_name, role_class)
|
66
|
+
@context = context
|
67
|
+
@role_name = role_name
|
68
|
+
@role_class = role_class
|
69
|
+
@role_list = Utils.get_role_list(@context, @role_name)
|
70
|
+
end
|
71
|
+
def eql?(o)
|
72
|
+
return false if o.class != self.class
|
73
|
+
context_equal = (@context == o.instance_variable_get(:@context))
|
74
|
+
role_equal = (@role_class == o.instance_variable_get(:@role_class))
|
75
|
+
context_equal and role_equal
|
76
|
+
end
|
77
|
+
def hash
|
78
|
+
(@context.hash | @role_class.hash)
|
79
|
+
end
|
80
|
+
def ==(o)
|
81
|
+
eql?(o)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
class RoleProxy < RoleProxyBase
|
86
|
+
private
|
87
|
+
def method_missing(name, *args)
|
88
|
+
HolderProxy.new(@role_list[0]).send(name, *args)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
class RolesProxy < RoleProxyBase
|
93
|
+
def initialize(context, role_name, role_class, default=nil)
|
94
|
+
super(context, role_name, role_class)
|
95
|
+
@default = default
|
96
|
+
end
|
97
|
+
|
98
|
+
def each(&block)
|
99
|
+
results = []
|
100
|
+
@role_list.each do |role_holder|
|
101
|
+
begin
|
102
|
+
results << block.call(HolderProxy.new(role_holder))
|
103
|
+
rescue
|
104
|
+
results << @default
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
private
|
109
|
+
def method_missing(name, *args)
|
110
|
+
results = []
|
111
|
+
@role_list.each do |role_holder|
|
112
|
+
begin
|
113
|
+
results << HolderProxy.new(role_holder).send(name, *args)
|
114
|
+
rescue
|
115
|
+
results << @default
|
116
|
+
end
|
117
|
+
end
|
118
|
+
return results
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
|
2
|
+
module Bunraku
|
3
|
+
module Utils
|
4
|
+
def self.get_role_class(context, role_name)
|
5
|
+
context.class.const_get(role_name)
|
6
|
+
end
|
7
|
+
def self.role_class?(context, role_name, role_class)
|
8
|
+
role_class.class == Class and
|
9
|
+
role_class.include? Role and
|
10
|
+
context.instance_variables.include?(role_list_name(role_name))
|
11
|
+
end
|
12
|
+
def self.get_role_list(context, role_name)
|
13
|
+
role_class = get_role_class(context, role_name)
|
14
|
+
return nil unless role_class?(context, role_name, role_class)
|
15
|
+
context.instance_variable_get(role_list_name(role_name))
|
16
|
+
end
|
17
|
+
def self.role_list_name(role_name)
|
18
|
+
"@" + role_name.to_s
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|