maroon 0.7.1 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|