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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +26 -6
  3. data/Rakefile +3 -3
  4. data/Test/Context_test.rb +16 -16
  5. data/{Examples/Dijkstra → Test/Examples}/CalculateShortestDistance.rb +11 -13
  6. data/Test/Examples/MoneyTransfer_test.rb +76 -0
  7. data/{Examples/Dijkstra → Test/Examples}/calculate_shortest_path.rb +77 -89
  8. data/{Examples/Dijkstra → Test/Examples}/data.rb +0 -0
  9. data/{Examples/Dijkstra/dijkstra.rb → Test/Examples/dijkstra_test.rb} +34 -24
  10. data/Test/Examples/greeter_test.rb +48 -0
  11. data/{Examples/meter.rb → Test/Examples/meter_test.rb} +44 -30
  12. data/Test/abstract_syntax_tree_test.rb +17 -26
  13. data/Test/alltests.rb +1 -1
  14. data/Test/test_helper.rb +2 -0
  15. data/base/AbstractSyntaxTree.rb +24 -3
  16. data/base/ImmutableStack.rb +1 -1
  17. data/base/dependency_graph.rb +94 -0
  18. data/base/immutable_queue.rb +1 -1
  19. data/base/maroon_base.rb +50 -11
  20. data/base/transfomer.rb +196 -197
  21. data/generated/Tokens.rb +64 -2
  22. data/generated/build.rb +1 -3
  23. data/generated/maroon/kernel.rb +7 -0
  24. data/lib/AbstractSyntaxTree.rb +120 -0
  25. data/lib/AstRewritter.rb +53 -58
  26. data/lib/Context.rb +104 -126
  27. data/lib/DependencyGraph.rb +76 -0
  28. data/lib/ImmutableQueue.rb +28 -39
  29. data/lib/ImmutableStack.rb +20 -34
  30. data/lib/Tokens.rb +64 -2
  31. data/lib/Transformer.rb +125 -165
  32. data/lib/build.rb +2 -4
  33. data/lib/maroon/kernel.rb +1 -1
  34. data/lib/maroon/version.rb +1 -1
  35. metadata +13 -11
  36. data/Examples/MoneyTransfer.rb +0 -62
  37. data/Examples/greeter.rb +0 -46
  38. data/Test/Greeter_test_disabled.rb +0 -203
  39. data/lib/Production.rb +0 -149
@@ -1,10 +1,14 @@
1
1
  # -*- encoding: utf-8 -*-
2
- require './Lib/maroon.rb'
3
- require './Examples/Dijkstra/data.rb'
4
- require './Examples/Dijkstra/CalculateShortestDistance.rb'
5
- require './Examples/Dijkstra/Calculate_Shortest_Path.rb'
2
+ require 'test/unit'
3
+ require_relative '../test_helper'
4
+ require_relative 'data.rb'
5
+ require_relative 'CalculateShortestDistance.rb'
6
+ require_relative 'Calculate_Shortest_Path.rb'
7
+
8
+
9
+ class DijkstraTest < Test::Unit::TestCase
6
10
  #!/usr/bin/env ruby
7
- # Example in Ruby -- Dijkstra's algorithm in DCI
11
+ # Example in Ruby -- DijkstraTest's algorithm in DCI
8
12
  # Modified and simplified for a Manhattan geometry with 8 roles
9
13
  #
10
14
  #
@@ -59,27 +63,33 @@ require './Examples/Dijkstra/Calculate_Shortest_Path.rb'
59
63
 
60
64
  # --- Main Program: test driver
61
65
  #
62
- geometries = Geometry_1.new
63
- path = CalculateShortestPath.new(geometries.root, geometries.destination, geometries)
64
- print 'Path is: '
65
- path.each { |node| print "#{node.name} " }
66
- print "\n"
67
- puts "distance is #{CalculateShortestDistance.new(geometries.root, geometries).distance}"
66
+ def test_geometry_1
67
+ geometries = Geometry_1.new
68
+ path = []
69
+ CalculateShortestPath.new(geometries.root, geometries.destination, geometries,nil,nil,nil,nil).each { |node| path << "#{node.name} " }
70
+ distance = CalculateShortestDistance.new(geometries.root, geometries).distance
71
+ assert_equal(["'i' ","'h' ","'g' ","'d' ","'a' "], path)
72
+ assert_equal(6,distance)
73
+ end
68
74
 
69
- puts ''
70
75
 
71
- geometries = ManhattanGeometry2.new
72
- path = CalculateShortestPath.new(geometries.root, geometries.destination, geometries)
73
- print 'Path is: '
74
- last_node = nil
75
- path.each do |node|
76
- if last_node != nil;
77
- print " - #{geometries.distances[Edge.new(node, last_node)]} - "
76
+ def test_geometry_2
77
+ geometries = ManhattanGeometry2.new
78
+ path = CalculateShortestPath.new(geometries.root, geometries.destination, geometries,nil,nil,nil,nil)
79
+
80
+ last_node = nil
81
+ res = []
82
+ result = []
83
+ path.each do |node|
84
+ if last_node != nil;
85
+ result << geometries.distances[Edge.new(node, last_node)]
86
+ end
87
+ res << "#{node.name}"
88
+ last_node = node
89
+ end
90
+ assert_equal([1,1,3,2], result)
91
+ assert_equal(["'k'", "'j'", "'c'", "'b'", "'a'"], res)
78
92
  end
79
- print "#{node.name}"
80
- last_node = node
81
93
  end
82
- print "\n"
83
94
 
84
- geometries = ManhattanGeometry2.new
85
- puts "distance is #{CalculateShortestDistance.new(geometries.root, geometries).distance }"
95
+
@@ -0,0 +1,48 @@
1
+ #Thanks to Ted Milken for updating the original example
2
+ require 'test/unit'
3
+ require_relative '../test_helper'
4
+
5
+ class Person
6
+ attr_accessor :name
7
+ attr_accessor :greeting
8
+ end
9
+
10
+ class GreeterTest < Test::Unit::TestCase
11
+ def test_greet
12
+ Context.generate_dependency_graph = true
13
+ Context.generate_code = true
14
+ ctx = Context.define :Greet_Someone do
15
+ role :greeter do
16
+ def welcome
17
+ greeter.greeting
18
+ end
19
+ end
20
+
21
+ role :greeted do
22
+ end
23
+
24
+ def greet
25
+ greeter.name.to_s + ': ' + greeter.welcome.to_s + ' ' + greeted.name.to_s + '!'
26
+ end
27
+
28
+ def initialize(greeter, greeted)
29
+ @greeter = greeter
30
+ @greeted = greeted
31
+ end
32
+ end
33
+
34
+ p1 = Person.new
35
+ p1.name = 'Bob'
36
+ p1.greeting = 'Hello'
37
+
38
+ p2 = Person.new
39
+ p2.name = 'World'
40
+ p2.greeting = 'Greetings'
41
+
42
+ res = Greet_Someone.new(p1, p2).greet
43
+ assert_equal("Bob: Hello World!",res)
44
+ puts ""
45
+ p ctx.dependencies.to_dot
46
+ end
47
+
48
+ end
@@ -1,41 +1,39 @@
1
+ require 'test/unit'
2
+ require_relative '../test_helper'
1
3
 
2
- require './lib/maroon/kernel'
4
+ context :Meter do
5
+ def initialize(clock, start_pos)
6
+ @clock = clock
7
+ @route = Route.new({0 => {1 => 1.25}}, Road_types.new)
8
+ route.update_position start_pos
9
+ @price_per_sec = 0.05
10
+ end
3
11
 
4
- context :Meter, :current_total do
5
- role :price_per_sec
12
+ role :price_per_sec do end
6
13
 
7
14
  role :route do
8
- price do
15
+ def price
9
16
  route.calculate_price clock.start
10
17
  end
11
18
  end
12
19
 
13
20
  role :clock do
14
- price do
15
- self.duration * price_per_sec
21
+ def price
22
+ clock.duration * price_per_sec
16
23
  end
17
24
  end
18
25
 
19
- current_total do |current_position|
26
+ def current_total(current_position)
20
27
  route.update_position current_position
21
28
  clock.price + route.price
22
29
  end
23
- print_route do
30
+ def print_route
24
31
  route.each_point { |x, y|
25
- p "#{x},#{y}"
32
+ p x.to_s + ' ' + y.to_s
26
33
  }
27
34
  end
28
35
  end
29
36
 
30
- class Meter
31
- def initialize(start, start_pos)
32
- @clock = Clock.new start
33
- @route = Route.new({0 => {1 => 1.25}}, Road_types.new)
34
- route.update_position start_pos
35
- @price_per_sec = 0.05
36
- end
37
- end
38
-
39
37
  class Clock
40
38
  attr_reader :start
41
39
 
@@ -52,37 +50,34 @@ context :Route do
52
50
  role :prices do
53
51
  end
54
52
  role :payable_position do
55
- price_from do |prev|
53
+ def price_from(prev)
56
54
  return 0 unless prev
57
- delta = Math.sqrt((prev.x-self.x)**2 + (prev.y-self.y)**2 + (prev.z-self.z)**2)
58
- road_type = @road_types[self]
55
+ delta = Math.sqrt((prev.x-payable_position.x)**2 + (prev.y-payable_position.y)**2 + (prev.z-payable_position.z)**2)
56
+ road_type = @road_types[payable_position]
59
57
  price = prices[road_type]
60
58
  delta * price
61
59
  end
62
60
  end
63
61
 
64
62
  role :positions do
65
- price_for_route do |price_table|
63
+ def price_for_route(price_table)
66
64
  prev = nil
67
65
  sum = 0
68
66
  positions.each do |pos|
69
- bind pos => :payable_position, price_table => :prices
70
- sum += pos.price_from prev
71
- prev = pos
67
+ bind :pos => :payable_position, :price_table => :prices
68
+ sum += payable_position.price_from prev
69
+ prev = payable_position
72
70
  end
73
71
  sum
74
72
  end
75
73
  end
76
- update_position do |new_position|
74
+ def update_position(new_position)
77
75
  positions << new_position
78
76
  end
79
- calculate_price do |start_time|
77
+ def calculate_price(start_time)
80
78
  price_table = prices[start_time.hour / (24/prices.length)]
81
79
  positions.price_for_route price_table
82
80
  end
83
- end
84
-
85
- class Route
86
81
  def initialize(prices, road_types)
87
82
  @positions = []
88
83
  @prices = prices
@@ -123,3 +118,22 @@ class Position
123
118
  @z = z
124
119
  end
125
120
  end
121
+
122
+ class MeterTest < Test::Unit::TestCase
123
+ class TestClock
124
+ def initialize(duration)
125
+ @duration = duration
126
+
127
+ end
128
+ def start
129
+ Time.now
130
+ end
131
+ attr_reader :duration
132
+ end
133
+
134
+ def test_run
135
+ meter = Meter.new(TestClock.new(100),Position.new(0,0,0))
136
+ price = meter.current_total Position.new(10,4,5)
137
+ assert_equal(19,price.to_i)
138
+ end
139
+ end
@@ -4,44 +4,35 @@ require_relative '../generated/AbstractSyntaxTree'
4
4
  require_relative 'test_helper'
5
5
 
6
6
  class AbstractSyntaxTreeTest < Test::Unit::TestCase
7
- def get_method_call &b
8
- exp = get_sexp &b
9
- exp[3]
10
- end
11
7
 
12
- def get_context(roles={},contracts={},role_aliases={},defining=nil,private_interactions= {})
13
- InterpretationContext.new(roles, contracts, role_aliases,defining,private_interactions)
8
+ def get_type_of_production(&b)
9
+ contracts ={}
10
+ roles = {:foo => {:bar => []}}
11
+ interpretation_context = InterpretationContext.new(roles, contracts, nil,nil,nil)
12
+
13
+ exp = get_sexp &b
14
+ method_call = exp[3]
15
+ production = AbstractSyntaxTree.new(method_call, interpretation_context )
16
+ production.type
14
17
  end
15
18
 
16
19
  def test_rolemethod
17
- method_call = get_method_call { foo.bar }
18
-
19
- production = get_production(method_call)
20
- type = production.type
20
+ type = get_type_of_production { foo.bar }
21
21
  assert_equal(Tokens::rolemethod_call, type)
22
22
  end
23
23
 
24
- def get_production(method_call)
25
- contracts ={}
26
- roles = {:foo => {:bar => []}}
27
- AbstractSyntaxTree.new(method_call, get_context(roles, contracts))
28
- end
29
-
30
24
  def test_call
31
- method_call = get_method_call { foo.baz }
32
-
33
- production = get_production(method_call)
34
- type = production.type
35
-
25
+ type = get_type_of_production { foo.baz }
36
26
  assert_equal(Tokens::call, type)
37
27
  end
38
28
 
39
- def test_indexer
40
- method_call = get_method_call { foo[0] }
41
-
42
- production = get_production(method_call)
43
- type = production.type
29
+ def test_initializer
30
+ type = get_type_of_production { AbstractSyntaxTreeTest.new(nil) }
31
+ assert_equal(Tokens::initializer, type)
32
+ end
44
33
 
34
+ def test_indexer
35
+ type = get_type_of_production { foo[0] }
45
36
  assert_equal(Tokens::indexer, type)
46
37
  end
47
38
  end
@@ -1 +1 @@
1
- `git ls-files`.split($/).grep(%r{(test|spec|features).rb}).select { |f| p f; require_relative("../#{f}") }
1
+ `git ls-files`.split($/).grep(%r{(test|spec|features).rb}).select { |f| p f; require_relative("../#{f}") }
@@ -2,6 +2,8 @@ require 'minitest/autorun'
2
2
  require 'sourcify'
3
3
  require_relative 'assertions'
4
4
  require_relative '../generated/build'
5
+ require_relative '../generated/maroon/kernel'
6
+
5
7
  #require 'debugger'
6
8
 
7
9
  def get_sexp &b
@@ -9,7 +9,7 @@ context :AbstractSyntaxTree do
9
9
 
10
10
  case
11
11
  when production.is_call? && (interpretation_context.roles.has_key?(production[2]))
12
- @date = [production[2]]
12
+ @data = [production[2]]
13
13
  return true
14
14
  when (production == :self ||
15
15
  (production.is_indexer? && (production[1] == nil || production[1] == :self)) ||
@@ -54,14 +54,31 @@ context :AbstractSyntaxTree do
54
54
  end
55
55
  end
56
56
  end
57
-
57
+ def is_const?
58
+ if production.instance_of?(Sexp) && production.length == 2 && production[0] == :const && (production[1].instance_of? Symbol)
59
+ @data = [production[1]]
60
+ true
61
+ else
62
+ false
63
+ end
64
+ end
65
+ def is_initializer?
66
+ if production.is_call?
67
+ if AbstractSyntaxTree.new(production[1], @interpretation_context).type == Tokens::const
68
+ if production[2] == :new
69
+ return true
70
+ end
71
+ end
72
+ end
73
+ false
74
+ end
58
75
  def is_rolemethod_call?
59
76
  can_be = production.is_call?
60
77
  if can_be
61
78
  instance = AbstractSyntaxTree.new(production[1], @interpretation_context)
62
79
  can_be = instance.type == Tokens::role
63
80
  if can_be
64
- instance_data = instance.data
81
+ instance_data = instance.data[0]
65
82
  role = @interpretation_context.roles[instance_data]
66
83
  data = production[2]
67
84
  can_be = role.has_key?(data)
@@ -93,6 +110,10 @@ context :AbstractSyntaxTree do
93
110
  Tokens::role
94
111
  when production.is_indexer?
95
112
  Tokens::indexer
113
+ when production.is_const?
114
+ Tokens::const
115
+ when production.is_initializer?
116
+ Tokens::initializer
96
117
  when production.is_call?
97
118
  Tokens::call
98
119
  else
@@ -13,7 +13,7 @@ context :ImmutableStack do
13
13
  end
14
14
 
15
15
  def self.empty
16
- @@empty ||= self.new(nil, nil)
16
+ @empty ||= self.new(nil, nil)
17
17
  end
18
18
 
19
19
  def each
@@ -0,0 +1,94 @@
1
+ context :DependencyGraph do
2
+
3
+ def initialize(context_name, roles, interactions, dependencies)
4
+ @context_name = context_name
5
+
6
+ @roles = roles
7
+ @interactions = interactions
8
+ @dependencies = dependencies
9
+ end
10
+
11
+ role :roles do
12
+ def dependencies
13
+ roles.each do |r, methods|
14
+ bind :r => :role_name
15
+ role_dependencies = (dependencies[r] ||= {})
16
+ methods.each do |name, method_sources|
17
+ bind :method_sources => :method, :role_dependencies => :dependency
18
+ method.get_dependencies
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ role :interactions do
25
+ def dependencies
26
+ interactions.each do |name, interact|
27
+ role_dependencies = ((dependencies[:interactions] ||= {})[name] ||= {})
28
+ interact.each do |m|
29
+ bind :m => :method, :role_dependencies => :dependency
30
+ method.get_dependencies
31
+ end
32
+ end
33
+ end
34
+ end
35
+ role :dependencies do end
36
+ role :dependency do
37
+ def add(dependent_role_name,method_name)
38
+ if dependent_role_name && dependent_role_name != role_name
39
+ dependency[dependent_role_name] ||= {}
40
+
41
+ unless dependency[dependent_role_name].has_key? method_name
42
+ dependency[dependent_role_name][method_name] = 0
43
+ end
44
+ dependency[dependent_role_name][method_name] += 1
45
+ end
46
+ end
47
+ end
48
+ role :role_name do end
49
+ role :method do
50
+ def body
51
+ args = method.definition.detect { |d| d[0] == :args }
52
+ index = method.definition.index(args) + 1
53
+ if method.definition.length > index+1
54
+ body = method.definition[index..-1]
55
+ body.insert(0, :block)
56
+ body
57
+ else
58
+ method.definition[index]
59
+ end
60
+ end
61
+
62
+ def ast
63
+ AbstractSyntaxTree.new(method.body, InterpretationContext.new(roles,{},{},role_name,{}))
64
+ end
65
+ def definition
66
+ (method.instance_of? Array) ? method[0] : method
67
+ end
68
+ def get_dependencies
69
+ method.ast.each_production do |production|
70
+ name = nil
71
+ method_name = nil
72
+ case production.type
73
+ when Tokens.rolemethod_call
74
+ data = production.data
75
+ name = data[1]
76
+ method_name = data[0]
77
+ when Tokens.role
78
+ name = production.data[0]
79
+ else
80
+ end
81
+ dependency.add(name,method_name) if name != nil
82
+ end
83
+ end
84
+ end
85
+
86
+ def create!
87
+ roles.dependencies
88
+ interactions.dependencies
89
+ dependencies
90
+ end
91
+
92
+
93
+ end
94
+