maroon 0.7.1 → 0.8.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.
- checksums.yaml +4 -4
- data/README.md +26 -6
- data/Rakefile +3 -3
- data/Test/Context_test.rb +16 -16
- data/{Examples/Dijkstra → Test/Examples}/CalculateShortestDistance.rb +11 -13
- data/Test/Examples/MoneyTransfer_test.rb +76 -0
- data/{Examples/Dijkstra → Test/Examples}/calculate_shortest_path.rb +77 -89
- data/{Examples/Dijkstra → Test/Examples}/data.rb +0 -0
- data/{Examples/Dijkstra/dijkstra.rb → Test/Examples/dijkstra_test.rb} +34 -24
- data/Test/Examples/greeter_test.rb +48 -0
- data/{Examples/meter.rb → Test/Examples/meter_test.rb} +44 -30
- data/Test/abstract_syntax_tree_test.rb +17 -26
- data/Test/alltests.rb +1 -1
- data/Test/test_helper.rb +2 -0
- data/base/AbstractSyntaxTree.rb +24 -3
- data/base/ImmutableStack.rb +1 -1
- data/base/dependency_graph.rb +94 -0
- data/base/immutable_queue.rb +1 -1
- data/base/maroon_base.rb +50 -11
- data/base/transfomer.rb +196 -197
- data/generated/Tokens.rb +64 -2
- data/generated/build.rb +1 -3
- data/generated/maroon/kernel.rb +7 -0
- data/lib/AbstractSyntaxTree.rb +120 -0
- data/lib/AstRewritter.rb +53 -58
- data/lib/Context.rb +104 -126
- data/lib/DependencyGraph.rb +76 -0
- data/lib/ImmutableQueue.rb +28 -39
- data/lib/ImmutableStack.rb +20 -34
- data/lib/Tokens.rb +64 -2
- data/lib/Transformer.rb +125 -165
- data/lib/build.rb +2 -4
- data/lib/maroon/kernel.rb +1 -1
- data/lib/maroon/version.rb +1 -1
- metadata +13 -11
- data/Examples/MoneyTransfer.rb +0 -62
- data/Examples/greeter.rb +0 -46
- data/Test/Greeter_test_disabled.rb +0 -203
- data/lib/Production.rb +0 -149
data/base/immutable_queue.rb
CHANGED
data/base/maroon_base.rb
CHANGED
@@ -10,7 +10,7 @@
|
|
10
10
|
# With in the block supplied to the role method you can define role methods the same way as you define interactions. See the method who
|
11
11
|
# in the below example
|
12
12
|
# = Example
|
13
|
-
# Context
|
13
|
+
# Context.define :Greeter do
|
14
14
|
# role :who do
|
15
15
|
# say do
|
16
16
|
# @who #could be self as well to refer to the current role player of the 'who' role
|
@@ -39,23 +39,62 @@ c = context :Context do
|
|
39
39
|
|
40
40
|
def self.define(*args, &block)
|
41
41
|
name, base_class, default_interaction = *args
|
42
|
+
|
42
43
|
if default_interaction and (not base_class.instance_of?(Class)) then
|
43
44
|
base_class = eval(base_class.to_s)
|
44
45
|
end
|
45
46
|
if base_class and ((not default_interaction) and (not base_class.instance_of?(Class))) then
|
46
47
|
base_class, default_interaction = default_interaction, base_class
|
47
48
|
end
|
48
|
-
|
49
|
-
|
50
|
-
ctx = self.send(:create_context_factory,
|
51
|
-
|
52
|
-
|
49
|
+
@with_contracts ||= nil
|
50
|
+
|
51
|
+
ctx = self.send(:create_context_factory, name, base_class, default_interaction, block)
|
52
|
+
|
53
|
+
if self.generate_dependency_graph
|
54
|
+
dependencies = {}
|
55
|
+
ctx.dependencies = DependencyGraphModel.new(DependencyGraph.new(name,ctx.roles,ctx.interactions,dependencies).create!)
|
56
|
+
end
|
57
|
+
transformer = Transformer.new(name, ctx.roles, ctx.interactions, ctx.private_interactions, base_class, default_interaction)
|
58
|
+
ctx.generated_class = transformer.transform(generate_files_in, @with_contracts)
|
59
|
+
ctx
|
53
60
|
end
|
54
61
|
|
55
|
-
def self.generate_files_in
|
62
|
+
def self.generate_files_in
|
63
|
+
@generate_files_in
|
64
|
+
end
|
56
65
|
|
57
|
-
|
66
|
+
def self.generate_files_in=(folder)
|
67
|
+
@generate_files_in = folder
|
68
|
+
end
|
58
69
|
|
70
|
+
def self.generate_code=(value)
|
71
|
+
@generate_code = value
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.generate_dependency_graph=(value)
|
75
|
+
@generate_dependency_graph = value
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.generate_code
|
79
|
+
@generate_code || !generate_dependency_graph || generate_files_in
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.generate_dependency_graph
|
83
|
+
@generate_dependency_graph
|
84
|
+
end
|
85
|
+
|
86
|
+
def dependencies
|
87
|
+
@dependencies
|
88
|
+
end
|
89
|
+
def generated_class
|
90
|
+
@generated_class
|
91
|
+
end
|
92
|
+
|
93
|
+
def dependencies=(value)
|
94
|
+
@dependencies=value
|
95
|
+
end
|
96
|
+
def generated_class=(value)
|
97
|
+
@generated_class=value
|
59
98
|
end
|
60
99
|
|
61
100
|
def roles
|
@@ -116,12 +155,12 @@ c = context :Context do
|
|
116
155
|
end
|
117
156
|
|
118
157
|
def self.with_contracts(*args)
|
119
|
-
return
|
158
|
+
return @with_contracts if (args.length == 0)
|
120
159
|
value = args[0]
|
121
|
-
if
|
160
|
+
if @with_contracts and (not value) then
|
122
161
|
raise('make up your mind! disabling contracts during execution will result in undefined behavior')
|
123
162
|
end
|
124
|
-
|
163
|
+
@with_contracts = value
|
125
164
|
|
126
165
|
end
|
127
166
|
|
data/base/transfomer.rb
CHANGED
@@ -1,197 +1,196 @@
|
|
1
|
-
context :Transformer do
|
2
|
-
|
3
|
-
def initialize(context_name, roles, interactions,private_interactions, base_class,default_interaction)
|
4
|
-
@context_name = context_name
|
5
|
-
|
6
|
-
@roles = roles
|
7
|
-
@interactions = interactions
|
8
|
-
@base_class = base_class
|
9
|
-
@default_interaction = default_interaction
|
10
|
-
@private_interactions = private_interactions
|
11
|
-
@definitions = {}
|
12
|
-
end
|
13
|
-
|
14
|
-
role :private_interactions do end
|
15
|
-
role :context_name do end
|
16
|
-
role :roles do
|
17
|
-
def generated_source
|
18
|
-
impl = ''
|
19
|
-
getters =
|
20
|
-
roles.each do |role, methods|
|
21
|
-
getters <<
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
definition
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
'
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
'
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
end
|
73
|
-
role :
|
74
|
-
role :
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
body
|
100
|
-
body
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
args
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
args
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
header
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
end
|
1
|
+
context :Transformer do
|
2
|
+
|
3
|
+
def initialize(context_name, roles, interactions,private_interactions, base_class,default_interaction)
|
4
|
+
@context_name = context_name
|
5
|
+
|
6
|
+
@roles = roles
|
7
|
+
@interactions = interactions
|
8
|
+
@base_class = base_class
|
9
|
+
@default_interaction = default_interaction
|
10
|
+
@private_interactions = private_interactions
|
11
|
+
@definitions = {}
|
12
|
+
end
|
13
|
+
|
14
|
+
role :private_interactions do end
|
15
|
+
role :context_name do end
|
16
|
+
role :roles do
|
17
|
+
def generated_source
|
18
|
+
impl = ''
|
19
|
+
getters = []
|
20
|
+
roles.each do |role, methods|
|
21
|
+
getters << role.to_s
|
22
|
+
methods.each do |name, method_sources|
|
23
|
+
bind :method_sources => :method , :name=> :method_name , :role => :defining_role
|
24
|
+
definition = method.generated_source
|
25
|
+
(impl << (' ' + definition )) if definition
|
26
|
+
end
|
27
|
+
end
|
28
|
+
(impl.strip! || '')+ '
|
29
|
+
' + (getters.length > 0 ? 'attr_reader :' +getters.join(', :') : '') + '
|
30
|
+
'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
role :interactions do
|
34
|
+
def generated_source
|
35
|
+
internal_methods = ''
|
36
|
+
external_methods = interactions.default
|
37
|
+
interactions.each do |name, interact|
|
38
|
+
interact.each do |m|
|
39
|
+
bind :m => :method, :name => :method_name
|
40
|
+
@defining_role = nil
|
41
|
+
code = method.generated_source
|
42
|
+
|
43
|
+
(method.is_private? ? internal_methods : external_methods) << ' ' << code
|
44
|
+
end
|
45
|
+
end
|
46
|
+
(external_methods.strip! || '') + '
|
47
|
+
private
|
48
|
+
' + (internal_methods.strip! || '') + '
|
49
|
+
'
|
50
|
+
end
|
51
|
+
def default
|
52
|
+
if @default
|
53
|
+
'
|
54
|
+
def self.call(*args)
|
55
|
+
arity = ' + name.to_s + '.method(:new).arity
|
56
|
+
newArgs = args[0..arity-1]
|
57
|
+
obj = ' + name.to_s + '.new *newArgs
|
58
|
+
if arity < args.length
|
59
|
+
methodArgs = args[arity..-1]
|
60
|
+
obj.' + default.to_s + ' *methodArgs
|
61
|
+
else
|
62
|
+
obj.' + default.to_s + '
|
63
|
+
end
|
64
|
+
end
|
65
|
+
def call(*args);' + default.to_s + ' *args; end
|
66
|
+
'
|
67
|
+
else
|
68
|
+
''
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
role :method_name do end
|
73
|
+
role :defining_role do end
|
74
|
+
role :method do
|
75
|
+
def is_private?
|
76
|
+
defining_role != nil || (private_interactions.has_key? method.name)
|
77
|
+
end
|
78
|
+
def definition
|
79
|
+
key = (@defining_role ? @defining_role.to_s : '') + method_name.to_s
|
80
|
+
return @definitions[key] if @definitions.has_key? key
|
81
|
+
unless method.instance_of? Sexp
|
82
|
+
unless (method.instance_of? Array) && method.length < 2 then
|
83
|
+
raise(('Duplicate definition of ' + method_name.to_s + '(' + method.to_s + ')'))
|
84
|
+
end
|
85
|
+
unless (method.instance_of? Array) && method.length > 0 then
|
86
|
+
raise(('No source for ' + method_name.to_s))
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
d = (method.instance_of? Array) ? method[0] : method
|
91
|
+
raise 'Sexp require' unless d.instance_of? Sexp
|
92
|
+
@definitions[key] = d
|
93
|
+
end
|
94
|
+
def body
|
95
|
+
args = method.definition.detect { |d| d[0] == :args }
|
96
|
+
index = method.definition.index(args) + 1
|
97
|
+
if method.definition.length > index+1
|
98
|
+
body = method.definition[index..-1]
|
99
|
+
body.insert(0, :block)
|
100
|
+
body
|
101
|
+
else
|
102
|
+
method.definition[index]
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def arguments
|
107
|
+
args = method.definition.detect { |d| d[0] == :args }
|
108
|
+
args && args.length > 1 ? args[1..-1] : []
|
109
|
+
end
|
110
|
+
|
111
|
+
def name
|
112
|
+
name = if method.definition[1].instance_of? Symbol
|
113
|
+
method.definition[1].to_s
|
114
|
+
else
|
115
|
+
(method.definition[1].select { |e| e.instance_of? Symbol }.map { |e| e.to_s }.join('.') + '.' + method.definition[2].to_s)
|
116
|
+
end
|
117
|
+
(
|
118
|
+
unless defining_role
|
119
|
+
name
|
120
|
+
else
|
121
|
+
'self_' + @defining_role.to_s + '_' + name.to_s
|
122
|
+
end).to_sym
|
123
|
+
end
|
124
|
+
def generated_source
|
125
|
+
AstRewritter.new(method.body, interpretation_context).rewrite!
|
126
|
+
body = Ruby2Ruby.new.process(method.body)
|
127
|
+
raise 'Body is undefined' unless body
|
128
|
+
args = method.arguments
|
129
|
+
if args && args.length
|
130
|
+
args = '('+ args.join(',') + ')'
|
131
|
+
else
|
132
|
+
args= ''
|
133
|
+
end
|
134
|
+
|
135
|
+
header = 'def ' + method.name.to_s + args
|
136
|
+
header + ' ' + body + ' end
|
137
|
+
'
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
|
142
|
+
def transform(file_path, with_contracts)
|
143
|
+
|
144
|
+
code = interactions.generated_source + roles.generated_source
|
145
|
+
|
146
|
+
if file_path then
|
147
|
+
name = context_name.to_s
|
148
|
+
complete = ((((('class ' + name) + (@base_class ? (('<< ' + @base_class.name)) : (''))) + '
|
149
|
+
') + code.to_s) + '
|
150
|
+
end')
|
151
|
+
File.open((((('./' + file_path.to_s) + '/') + name) + '.rb'), 'w') do |f|
|
152
|
+
f.write(complete)
|
153
|
+
end
|
154
|
+
complete
|
155
|
+
else
|
156
|
+
c = @base_class ? (Class.new(base_class)) : (Class.new)
|
157
|
+
if with_contracts then
|
158
|
+
c.class_eval(
|
159
|
+
'def self.assert_that(obj)
|
160
|
+
ContextAsserter.new(self.contracts,obj)
|
161
|
+
end
|
162
|
+
def self.refute_that(obj)
|
163
|
+
ContextAsserter.new(self.contracts,obj,false)
|
164
|
+
end
|
165
|
+
def self.contracts
|
166
|
+
@contracts
|
167
|
+
end
|
168
|
+
def self.contracts=(value)
|
169
|
+
@contracts = value
|
170
|
+
end')
|
171
|
+
c.contracts = contracts
|
172
|
+
end
|
173
|
+
Kernel.const_set(context_name, c)
|
174
|
+
begin
|
175
|
+
temp = c.class_eval(code)
|
176
|
+
rescue SyntaxError
|
177
|
+
p 'error: ' + code
|
178
|
+
end
|
179
|
+
|
180
|
+
(temp or c)
|
181
|
+
end
|
182
|
+
|
183
|
+
end
|
184
|
+
|
185
|
+
private
|
186
|
+
|
187
|
+
def contracts
|
188
|
+
(@contracts ||= {})
|
189
|
+
end
|
190
|
+
def role_aliases
|
191
|
+
(@role_aliases ||={})
|
192
|
+
end
|
193
|
+
def interpretation_context
|
194
|
+
InterpretationContext.new(roles, contracts, role_aliases, defining_role, @private_interactions)
|
195
|
+
end
|
196
|
+
end
|