maroon 0.6.1 → 0.6.5
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/Examples/Dijkstra/CalculateShortestDistance.rb +16 -12
- data/Examples/Dijkstra/calculate_shortest_path.rb +47 -27
- data/Examples/Dijkstra/data.rb +41 -14
- data/Examples/Dijkstra/dijkstra.rb +4 -3
- data/Examples/MoneyTransfer.rb +61 -60
- data/Examples/greeter.rb +8 -7
- data/Examples/meter.rb +35 -29
- data/Gemfile +9 -4
- data/LICENSE.txt +21 -21
- data/README.md +13 -0
- data/Rakefile +41 -1
- data/Test/Generate/method_info_test.rb +12 -0
- data/Test/{Greeter_test.rb → Greeter_test_disabled.rb} +24 -20
- data/Test/ImmutableQueue_test.rb +18 -0
- data/Test/MethodInfo_test.rb +65 -0
- data/Test/alltests.rb +1 -0
- data/Test/{source_assertions.rb → assertions.rb} +15 -7
- data/Test/bind_test.rb +13 -0
- data/Test/expression_test.rb +105 -0
- data/Test/method_call_test.rb +83 -0
- data/Test/self_test.rb +46 -0
- data/Test/stack_test.rb +17 -0
- data/Test/test_helper.rb +14 -0
- data/base/ImmutableStack.rb +32 -0
- data/base/MethodDefinition.rb +124 -0
- data/base/bind_rewriter.rb +58 -0
- data/base/immutable_queue.rb +50 -0
- data/base/maroon_base.rb +267 -0
- data/base/method_call.rb +78 -0
- data/base/method_info.rb +86 -0
- data/base/self.rb +60 -0
- data/generated/build.rb +13 -0
- data/generated/interpretation_context.rb +29 -0
- data/lib/Bind.rb +65 -0
- data/lib/Context.rb +187 -0
- data/lib/ImmutableQueue.rb +50 -0
- data/lib/ImmutableStack.rb +38 -0
- data/lib/MethodCall.rb +91 -0
- data/lib/MethodDefinition.rb +114 -0
- data/lib/MethodInfo.rb +78 -0
- data/lib/Self.rb +71 -0
- data/lib/build.rb +14 -0
- data/lib/interpretation_context.rb +30 -0
- data/lib/maroon/contracts.rb +43 -0
- data/lib/maroon/kernel.rb +2 -0
- data/lib/maroon/version.rb +3 -3
- data/maroon.gemspec +26 -26
- metadata +49 -31
- data/lib/Source_cleaner.rb +0 -34
- data/lib/maroon.rb +0 -165
- data/lib/rewriter.rb +0 -185
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a2b4446ac84c36b68f710a04280f9488d116035c
|
4
|
+
data.tar.gz: 01322628719027b5cfc4b500f81063a23c326e5a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8a6644383356d9c8939dd1fa94c89d0e89baa05d867a1c7f2229c335972c04c164d4e6deacbe0632a679453c60858eb3447914817c8d9bc1e6fd7b1a741dd2ae
|
7
|
+
data.tar.gz: ae022ce8665b2c78f963112be9a0635306dc6c47d64110dbde15508bdd690ba975ab3f14d2f1711c94e694d99fba2a19fa9af33a987fa484097992a94a57828d
|
@@ -1,10 +1,14 @@
|
|
1
1
|
Context::define :CalculateShortestDistance do
|
2
2
|
|
3
|
-
role :tentative_distance_values do
|
4
|
-
|
3
|
+
role :tentative_distance_values do
|
4
|
+
end
|
5
|
+
role :path do
|
6
|
+
end
|
5
7
|
|
6
|
-
role :current do
|
7
|
-
|
8
|
+
role :current do
|
9
|
+
end
|
10
|
+
role :destination do
|
11
|
+
end
|
8
12
|
|
9
13
|
|
10
14
|
role :map do
|
@@ -44,14 +48,14 @@ Context::define :CalculateShortestDistance do
|
|
44
48
|
@path = CalculateShortestPath.new(current, destination, map).path
|
45
49
|
retval = 0
|
46
50
|
previous_node = nil
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
51
|
+
path.reverse_each { |node|
|
52
|
+
if previous_node.nil?
|
53
|
+
retval = 0
|
54
|
+
else
|
55
|
+
retval += map.distance_between previous_node, node
|
56
|
+
end
|
57
|
+
previous_node = node
|
58
|
+
}
|
55
59
|
retval
|
56
60
|
end
|
57
61
|
|
@@ -2,7 +2,7 @@
|
|
2
2
|
#
|
3
3
|
# Consider street corners on a Manhattan grid. We want to find the
|
4
4
|
# minimal path from the most northeast city to the most
|
5
|
-
# southeast city. Use
|
5
|
+
# southeast city. Use Dijkstra's algorithm
|
6
6
|
#
|
7
7
|
|
8
8
|
|
@@ -15,7 +15,6 @@
|
|
15
15
|
#
|
16
16
|
|
17
17
|
|
18
|
-
|
19
18
|
# There are eight roles in the algorithm:
|
20
19
|
#
|
21
20
|
# pathTo, which is the interface to whatever accumulates the path
|
@@ -39,7 +38,7 @@
|
|
39
38
|
#
|
40
39
|
# Map is a DCI role. The role in this example is played by an
|
41
40
|
# object representing a particular Manhattan geometry
|
42
|
-
|
41
|
+
ctx, source = Context::define :CalculateShortestPath do
|
43
42
|
role :distance_labeled_graph_node do
|
44
43
|
# Access to roles and other Context data
|
45
44
|
tentative_distance_values do
|
@@ -58,17 +57,17 @@
|
|
58
57
|
role :map do
|
59
58
|
distance_between do |a, b|
|
60
59
|
dist = @map.distances[Edge.new(a, b)]
|
61
|
-
|
60
|
+
# p "distance between #{a.name} and #{b.name} is #{dist}"
|
62
61
|
dist
|
63
62
|
end
|
64
63
|
next_down_the_street_from do |x|
|
65
64
|
n = east_neighbor_of x
|
66
|
-
|
65
|
+
# p "next down the street from #{x.name} is #{n.name}"
|
67
66
|
n
|
68
67
|
end
|
69
68
|
next_along_the_avenue_from do |x|
|
70
69
|
n = south_neighbor_of x
|
71
|
-
|
70
|
+
# p "next along the avenue from #{x.name} is #{n.name}"
|
72
71
|
n
|
73
72
|
end
|
74
73
|
origin do
|
@@ -79,11 +78,11 @@
|
|
79
78
|
selection = nil
|
80
79
|
@unvisited.each_key {
|
81
80
|
|intersection|
|
82
|
-
bind :intersection
|
81
|
+
bind :intersection => :distance_labeled_graph_node
|
83
82
|
if @unvisited[intersection]
|
84
83
|
tentative_distance = intersection.tentative_distance
|
85
84
|
if tentative_distance < min
|
86
|
-
|
85
|
+
# p "min distance is updated from #{min} to #{tentative_distance}"
|
87
86
|
min = tentative_distance
|
88
87
|
selection = intersection
|
89
88
|
end
|
@@ -106,12 +105,16 @@
|
|
106
105
|
unvisited_neighbors do
|
107
106
|
retval = Array.new
|
108
107
|
if @south_neighbor != nil
|
109
|
-
if unvisited[@south_neighbor] then
|
108
|
+
if unvisited[@south_neighbor] then
|
109
|
+
retval << @south_neighbor
|
110
|
+
end
|
110
111
|
end
|
111
112
|
if @east_neighbor != nil
|
112
|
-
if unvisited[@east_neighbor] then
|
113
|
+
if unvisited[@east_neighbor] then
|
114
|
+
retval << @east_neighbor
|
115
|
+
end
|
113
116
|
end
|
114
|
-
|
117
|
+
# p "unvisited neighbors #{retval}"
|
115
118
|
retval
|
116
119
|
end
|
117
120
|
tentative_distance do
|
@@ -119,7 +122,8 @@
|
|
119
122
|
@tentative_distance_values[current]
|
120
123
|
end
|
121
124
|
end
|
122
|
-
role :unvisited do
|
125
|
+
role :unvisited do
|
126
|
+
end
|
123
127
|
|
124
128
|
|
125
129
|
# This module serves to provide the methods both for the
|
@@ -131,11 +135,11 @@
|
|
131
135
|
raise "self can't be nil" unless @neighbor_node
|
132
136
|
|
133
137
|
if x < neighbor_node.tentative_distance
|
134
|
-
|
138
|
+
# p "updated tentative distance from #{neighbor_node.tentative_distance} to #{x}"
|
135
139
|
neighbor_node.set_tentative_distance_to x
|
136
140
|
:distance_was_udated
|
137
141
|
else
|
138
|
-
|
142
|
+
# p "left tentative distance at #{neighbor_node.tentative_distance} instead of #{x}"
|
139
143
|
:distance_was_not_udated
|
140
144
|
end
|
141
145
|
end
|
@@ -151,7 +155,7 @@
|
|
151
155
|
tentative_distance_values[@neighbor_node] = x
|
152
156
|
end
|
153
157
|
end
|
154
|
-
|
158
|
+
# This is the method that starts the work. Called from initialize.
|
155
159
|
|
156
160
|
execute do |path_vector, unvisited_hash, pathto_hash, tentative_distance_values_hash|
|
157
161
|
do_inits(path_vector, unvisited_hash, pathto_hash,
|
@@ -161,7 +165,7 @@
|
|
161
165
|
# Calculate tentative distances of unvisited neighbors
|
162
166
|
|
163
167
|
unvisited_neighbors = current.unvisited_neighbors
|
164
|
-
|
168
|
+
# p "#{unvisited_neighbors}"
|
165
169
|
if unvisited_neighbors != nil
|
166
170
|
unvisited_neighbors.each {
|
167
171
|
|neighbor|
|
@@ -173,9 +177,9 @@
|
|
173
177
|
net_distance = tentative_distance + distance_between
|
174
178
|
|
175
179
|
if neighbor.relable_node_as(net_distance) == :distance_was_udated
|
176
|
-
|
180
|
+
# p "set path"
|
177
181
|
pathTo[neighbor] = @current
|
178
|
-
|
182
|
+
# p "path #{@pathTo}"
|
179
183
|
end
|
180
184
|
}
|
181
185
|
end
|
@@ -218,7 +222,7 @@
|
|
218
222
|
# These initializations are directly from the description of the algorithm
|
219
223
|
map.nodes.each { |node| @unvisited[node] = true }
|
220
224
|
@unvisited.delete(map.origin)
|
221
|
-
map.nodes.each { |node| bind :node
|
225
|
+
map.nodes.each { |node| bind :node => :distance_labeled_graph_node; node.set_tentative_distance_to(infinity) }
|
222
226
|
tentative_distance_values[map.origin] = 0
|
223
227
|
|
224
228
|
# The path array is kept in the outermost context and serves to store the
|
@@ -244,6 +248,7 @@
|
|
244
248
|
@pathTo = pathto_hash
|
245
249
|
end
|
246
250
|
end
|
251
|
+
|
247
252
|
# Since path_vector isn't set up, this is the first iteration of the recursion
|
248
253
|
|
249
254
|
@tentative_distance_values = Hash.new
|
@@ -257,11 +262,11 @@
|
|
257
262
|
# These initializations are directly from the description of the algorithm
|
258
263
|
map.nodes.each { |node| @unvisited[node] = true }
|
259
264
|
@unvisited.delete(map.origin)
|
260
|
-
|
265
|
+
# p "map #{map.nodes}"
|
261
266
|
map.nodes.each { |node|
|
262
267
|
bind :node => :distance_labeled_graph_node;
|
263
268
|
node.set_tentative_distance_to(infinity)
|
264
|
-
|
269
|
+
# p "initialized node #{node.name}"
|
265
270
|
}
|
266
271
|
tentative_distance_values[map.origin] = 0
|
267
272
|
|
@@ -297,12 +302,26 @@ class CalculateShortestPath
|
|
297
302
|
def pathTo
|
298
303
|
@pathTo
|
299
304
|
end
|
300
|
-
def east_neighbor; @east_neighbor end
|
301
|
-
def south_neighbor; @south_neighbor end
|
302
|
-
def path; @path end
|
303
305
|
|
304
|
-
def
|
305
|
-
|
306
|
+
def east_neighbor;
|
307
|
+
@east_neighbor
|
308
|
+
end
|
309
|
+
|
310
|
+
def south_neighbor;
|
311
|
+
@south_neighbor
|
312
|
+
end
|
313
|
+
|
314
|
+
def path;
|
315
|
+
@path
|
316
|
+
end
|
317
|
+
|
318
|
+
def destination;
|
319
|
+
@destination
|
320
|
+
end
|
321
|
+
|
322
|
+
def tentative_distance_values;
|
323
|
+
@tentative_distance_values
|
324
|
+
end
|
306
325
|
|
307
326
|
# This is a shortcut to information that really belongs in the Map.
|
308
327
|
# To keep roles stateless, we hold the Map's unvisited structure in the
|
@@ -333,6 +352,7 @@ class CalculateShortestPath
|
|
333
352
|
|
334
353
|
execute(path_vector, unvisited_hash, pathto_hash, tentative_distance_values_hash)
|
335
354
|
end
|
355
|
+
|
336
356
|
def each
|
337
357
|
path.each { |node| yield node }
|
338
358
|
end
|
@@ -350,5 +370,5 @@ class CalculateShortestPath
|
|
350
370
|
end
|
351
371
|
end
|
352
372
|
|
353
|
-
File.open('CalculateShortestPath_generated.rb', 'w') {|f| f.write(source) }
|
373
|
+
File.open('CalculateShortestPath_generated.rb', 'w') { |f| f.write(source) }
|
354
374
|
|
data/Examples/Dijkstra/data.rb
CHANGED
@@ -1,10 +1,17 @@
|
|
1
|
-
def infinity;
|
1
|
+
def infinity;
|
2
|
+
(2**(0.size * 8 -2) -1)
|
3
|
+
end
|
4
|
+
|
2
5
|
# Data classes
|
3
6
|
Edge = Struct.new(:from, :to)
|
4
7
|
|
5
8
|
class Node
|
6
9
|
attr_reader :name
|
7
|
-
|
10
|
+
|
11
|
+
def initialize(n)
|
12
|
+
; @name = n
|
13
|
+
end
|
14
|
+
|
8
15
|
def eql? (another_node)
|
9
16
|
# Nodes are == equal if they have the same name. This is explicitly
|
10
17
|
# defined here to call out the importance of the differnce between
|
@@ -14,7 +21,6 @@ class Node
|
|
14
21
|
end
|
15
22
|
|
16
23
|
|
17
|
-
|
18
24
|
#
|
19
25
|
# --- Geometry is the interface to the data class that has all
|
20
26
|
# --- the information about the map. This is kind of silly in Ruby
|
@@ -25,14 +31,16 @@ class ManhattanGeometry
|
|
25
31
|
@distances = Hash.new
|
26
32
|
end
|
27
33
|
|
28
|
-
def nodes;
|
34
|
+
def nodes;
|
35
|
+
@nodes
|
36
|
+
end
|
37
|
+
|
29
38
|
def distances
|
30
39
|
@distances
|
31
40
|
end
|
32
41
|
end
|
33
42
|
|
34
43
|
|
35
|
-
|
36
44
|
#
|
37
45
|
# --- Here are some test data
|
38
46
|
#
|
@@ -49,7 +57,6 @@ class Geometry_1 < ManhattanGeometry
|
|
49
57
|
nodes << Node.new(names[(i*3)+j])
|
50
58
|
}
|
51
59
|
}
|
52
|
-
|
53
60
|
|
54
61
|
|
55
62
|
# Aliases to help set up the grid. Grid is of Manhattan form:
|
@@ -114,11 +121,21 @@ class Geometry_1 < ManhattanGeometry
|
|
114
121
|
@next_along_the_avenue_from.freeze
|
115
122
|
end
|
116
123
|
|
117
|
-
def east_neighbor_of(a)
|
118
|
-
|
124
|
+
def east_neighbor_of(a)
|
125
|
+
; @next_down_the_street_from[a]
|
126
|
+
end
|
119
127
|
|
120
|
-
def
|
121
|
-
|
128
|
+
def south_neighbor_of(a)
|
129
|
+
; @next_along_the_avenue_from[a]
|
130
|
+
end
|
131
|
+
|
132
|
+
def root;
|
133
|
+
@node_a
|
134
|
+
end
|
135
|
+
|
136
|
+
def destination;
|
137
|
+
@node_i
|
138
|
+
end
|
122
139
|
end
|
123
140
|
|
124
141
|
|
@@ -201,10 +218,20 @@ class ManhattanGeometry2 < ManhattanGeometry
|
|
201
218
|
@next_along_the_avenue_from.freeze
|
202
219
|
end
|
203
220
|
|
204
|
-
def east_neighbor_of(a)
|
205
|
-
|
221
|
+
def east_neighbor_of(a)
|
222
|
+
; @next_down_the_street_from[a]
|
223
|
+
end
|
224
|
+
|
225
|
+
def south_neighbor_of(a)
|
226
|
+
; @next_along_the_avenue_from[a]
|
227
|
+
end
|
206
228
|
|
207
|
-
def root;
|
208
|
-
|
229
|
+
def root;
|
230
|
+
@node_a
|
231
|
+
end
|
232
|
+
|
233
|
+
def destination;
|
234
|
+
@node_k
|
235
|
+
end
|
209
236
|
end
|
210
237
|
|
@@ -57,7 +57,6 @@ require './Examples/Dijkstra/Calculate_Shortest_Path.rb'
|
|
57
57
|
# design
|
58
58
|
|
59
59
|
|
60
|
-
|
61
60
|
# --- Main Program: test driver
|
62
61
|
#
|
63
62
|
geometries = Geometry_1.new
|
@@ -74,11 +73,13 @@ path = CalculateShortestPath.new(geometries.root, geometries.destination, geomet
|
|
74
73
|
print 'Path is: '
|
75
74
|
last_node = nil
|
76
75
|
path.each do |node|
|
77
|
-
if last_node != nil;
|
76
|
+
if last_node != nil;
|
77
|
+
print " - #{geometries.distances[Edge.new(node, last_node)]} - "
|
78
|
+
end
|
78
79
|
print "#{node.name}"
|
79
80
|
last_node = node
|
80
81
|
end
|
81
82
|
print "\n"
|
82
83
|
|
83
84
|
geometries = ManhattanGeometry2.new
|
84
|
-
puts "distance is #{CalculateShortestDistance.new(geometries.root,
|
85
|
+
puts "distance is #{CalculateShortestDistance.new(geometries.root, geometries).distance }"
|
data/Examples/MoneyTransfer.rb
CHANGED
@@ -1,61 +1,62 @@
|
|
1
|
-
require './lib/maroon.rb'
|
2
|
-
|
3
|
-
Context::define :MoneyTransfer do
|
4
|
-
role :source do
|
5
|
-
withdraw do |amount|
|
6
|
-
source.movement(amount)
|
7
|
-
source.log "withdrawal #{amount}"
|
8
|
-
end
|
9
|
-
log do |message|
|
10
|
-
p "#{@source} source #{message}"
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
role :destination do
|
15
|
-
deposit do |amount|
|
16
|
-
@destination.movement(amount)
|
17
|
-
@destination.log "deposit #{amount}"
|
18
|
-
end
|
19
|
-
logger do |message|
|
20
|
-
p "#{@source} destination #{message}"
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
role :amount do
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
end
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
@
|
36
|
-
@
|
37
|
-
|
38
|
-
end
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
@
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
end
|
58
|
-
|
59
|
-
|
60
|
-
|
1
|
+
require './lib/maroon.rb'
|
2
|
+
|
3
|
+
Context::define :MoneyTransfer do
|
4
|
+
role :source do
|
5
|
+
withdraw do |amount|
|
6
|
+
source.movement(amount)
|
7
|
+
source.log "withdrawal #{amount}"
|
8
|
+
end
|
9
|
+
log do |message|
|
10
|
+
p "#{@source} source #{message}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
role :destination do
|
15
|
+
deposit do |amount|
|
16
|
+
@destination.movement(amount)
|
17
|
+
@destination.log "deposit #{amount}"
|
18
|
+
end
|
19
|
+
logger do |message|
|
20
|
+
p "#{@source} destination #{message}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
role :amount do
|
25
|
+
end
|
26
|
+
|
27
|
+
transfer do
|
28
|
+
source.withdraw -amount
|
29
|
+
destination.deposit amount
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class MoneyTransfer
|
34
|
+
def initialize(source, destination, amount)
|
35
|
+
@source = source
|
36
|
+
@destination = destination
|
37
|
+
@amount = amount
|
38
|
+
end
|
39
|
+
end
|
40
|
+
class Account
|
41
|
+
def initialize (amount, id)
|
42
|
+
@balance = amount
|
43
|
+
@account_id = id
|
44
|
+
end
|
45
|
+
|
46
|
+
def movement(amount)
|
47
|
+
log "Amount #{amount}"
|
48
|
+
@balance+=amount
|
49
|
+
end
|
50
|
+
|
51
|
+
def log(message)
|
52
|
+
(p s = "instance #{message}")
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_s
|
56
|
+
"balance of #{@account_id}: #{@balance}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
account = Account.new 1000, "source"
|
61
|
+
ctx = MoneyTransfer.new account, account, 100
|
61
62
|
ctx.transfer
|