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