gisele 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +33 -13
- data/Gemfile +3 -2
- data/Gemfile.lock +6 -3
- data/LICENCE.md +1 -1
- data/README.md +5 -2
- data/Rakefile +0 -8
- data/examples/rectal-cancer-pathway/RectalCancerPathway.gis +1 -1
- data/gisele.gemspec +3 -2
- data/gisele.noespec +4 -3
- data/lib/gisele.rb +11 -7
- data/lib/gisele/command.rb +28 -19
- data/lib/gisele/compiling.rb +2 -0
- data/lib/gisele/compiling/to_glts.rb +125 -0
- data/lib/gisele/compiling/to_graph.rb +160 -0
- data/lib/gisele/compiling/to_graph.yml +20 -0
- data/lib/gisele/language.rb +22 -36
- data/lib/gisele/language/ast/bool_and.rb +1 -1
- data/lib/gisele/language/ast/bool_expr.rb +9 -1
- data/lib/gisele/language/ast/bool_not.rb +1 -1
- data/lib/gisele/language/ast/bool_or.rb +1 -1
- data/lib/gisele/language/ast/case_st.rb +1 -1
- data/lib/gisele/language/ast/else_clause.rb +1 -1
- data/lib/gisele/language/ast/node.rb +4 -66
- data/lib/gisele/language/grammar.citrus +2 -2
- data/lib/gisele/language/grammar.sexp.yml +83 -80
- data/lib/gisele/language/processors.rb +2 -2
- data/lib/gisele/language/processors/elsif_flattener.rb +14 -13
- data/lib/gisele/language/processors/if_to_case.rb +20 -18
- data/lib/gisele/language/processors/scoping_helper.rb +32 -0
- data/lib/gisele/language/processors/sugar_removal.rb +10 -5
- data/lib/gisele/language/syntax/case_st.rb +1 -1
- data/lib/gisele/language/syntax/node.rb +6 -2
- data/lib/gisele/language/syntax/when_clause.rb +1 -1
- data/lib/gisele/loader.rb +2 -1
- data/lib/gisele/version.rb +1 -1
- data/spec/command/main/gisele_glts.cmd +1 -0
- data/spec/command/main/gisele_glts.stdout +85 -0
- data/spec/command/main/gisele_help.stdout +3 -2
- data/spec/spec_helper.rb +2 -3
- data/spec/test_examples.rb +2 -2
- data/spec/unit/compiling/test_to_glts.rb +20 -0
- data/spec/unit/compiling/test_to_graph.rb +19 -0
- data/spec/unit/language/ast/test_bool_expr.rb +50 -0
- data/spec/unit/language/grammar_sexp/test_fluent_def.rb +1 -1
- data/spec/unit/language/processors/test_elsif_flattener.rb +3 -3
- data/spec/unit/language/processors/test_if_to_case.rb +7 -7
- data/spec/unit/language/processors/test_scoping_helper.rb +45 -0
- data/spec/unit/language/syntax/grammar/test_bool_expr.rb +2 -2
- data/spec/unit/language/syntax/grammar/test_boolean_literal.rb +2 -2
- data/spec/unit/language/syntax/grammar/test_case_st.rb +2 -2
- data/spec/unit/language/syntax/grammar/test_event.rb +2 -2
- data/spec/unit/language/syntax/grammar/test_event_name.rb +2 -2
- data/spec/unit/language/syntax/grammar/test_event_set.rb +2 -3
- data/spec/unit/language/syntax/grammar/test_fluent_def.rb +2 -2
- data/spec/unit/language/syntax/grammar/test_if_st.rb +2 -2
- data/spec/unit/language/syntax/grammar/test_par_st.rb +2 -2
- data/spec/unit/language/syntax/grammar/test_process_statement.rb +2 -2
- data/spec/unit/language/syntax/grammar/test_seq_st.rb +2 -2
- data/spec/unit/language/syntax/grammar/test_spaces.rb +2 -2
- data/spec/unit/language/syntax/grammar/test_spacing.rb +2 -3
- data/spec/unit/language/syntax/grammar/test_task_def.rb +2 -2
- data/spec/unit/language/syntax/grammar/test_task_name.rb +2 -2
- data/spec/unit/language/syntax/grammar/test_task_start_or_end.rb +2 -2
- data/spec/unit/language/syntax/grammar/test_trackvar_def.rb +2 -2
- data/spec/unit/language/syntax/grammar/test_unit_def.rb +2 -2
- data/spec/unit/language/syntax/grammar/test_variable_name.rb +24 -3
- data/spec/unit/language/syntax/grammar/test_when_clause.rb +2 -2
- data/spec/unit/language/syntax/grammar/test_while_st.rb +2 -2
- data/spec/unit/language/syntax/to_ast/test_bool_expr.rb +5 -1
- data/spec/unit/language/syntax/to_ast/test_case_st.rb +1 -1
- data/spec/unit/language/syntax/to_ast/test_else_clause.rb +1 -1
- data/spec/unit/language/syntax/to_ast/test_elsif_clause.rb +1 -1
- data/spec/unit/language/syntax/to_ast/test_event_set.rb +1 -1
- data/spec/unit/language/syntax/to_ast/test_fluent_def.rb +1 -1
- data/spec/unit/language/syntax/to_ast/test_if_st.rb +1 -1
- data/spec/unit/language/syntax/to_ast/test_par_st.rb +1 -1
- data/spec/unit/language/syntax/to_ast/test_seq_st.rb +1 -1
- data/spec/unit/language/syntax/to_ast/test_task_call_st.rb +1 -1
- data/spec/unit/language/syntax/to_ast/test_task_def.rb +1 -1
- data/spec/unit/language/syntax/to_ast/test_trackvar_def.rb +1 -1
- data/spec/unit/language/syntax/to_ast/test_unit_def.rb +1 -1
- data/spec/unit/language/syntax/to_ast/test_var_ref.rb +1 -1
- data/spec/unit/language/syntax/to_ast/test_when_clause.rb +1 -1
- data/spec/unit/language/syntax/to_ast/test_while_st.rb +1 -1
- data/spec/unit/language/test_syntax.rb +36 -38
- data/spec/unit/test_gisele.rb +1 -1
- metadata +189 -190
- data/lib/gisele/language/ast.rb +0 -14
- data/lib/gisele/language/ast/helpers.rb +0 -43
- data/lib/gisele/language/ast/unit_def.rb +0 -10
- data/lib/gisele/language/grammar.dot.yml +0 -19
- data/lib/gisele/language/processors/to_graph.rb +0 -146
- data/lib/gisele/language/rewriter.rb +0 -60
- data/lib/gisele/language/rewriter/helper.rb +0 -41
- data/lib/gisele/language/rewriter/scoping.rb +0 -34
- data/lib/gisele/language/rewriter/work_on_nodes.rb +0 -30
- data/lib/gisele/language/syntax.rb +0 -29
- data/spec/unit/language/ast/test_node.rb +0 -82
- data/spec/unit/language/processors/test_to_graph.rb +0 -17
- data/spec/unit/language/rewriter/test_helper.rb +0 -87
- data/spec/unit/language/rewriter/test_scoping.rb +0 -46
- data/spec/unit/language/rewriter/test_work_on_nodes.rb +0 -45
- data/spec/unit/language/test_ast.rb +0 -38
- data/spec/unit/language/test_rewriter.rb +0 -81
- data/spec/unit/test_language.rb +0 -35
data/lib/gisele/language/ast.rb
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
module Gisele
|
2
|
-
module Language
|
3
|
-
module AST
|
4
|
-
|
5
|
-
def node(arg, markers = {})
|
6
|
-
AST::Helpers.node(arg, markers)
|
7
|
-
end
|
8
|
-
module_function :node
|
9
|
-
|
10
|
-
end # module AST
|
11
|
-
end # module Language
|
12
|
-
end # module Gisele
|
13
|
-
require_relative 'ast/helpers'
|
14
|
-
require_relative 'ast/node'
|
@@ -1,43 +0,0 @@
|
|
1
|
-
module Gisele
|
2
|
-
module Language
|
3
|
-
module AST
|
4
|
-
module Helpers
|
5
|
-
|
6
|
-
def ast(arg, markers = {})
|
7
|
-
return node(arg, markers) if looks_a_node?(arg)
|
8
|
-
ast(Syntax.ast(arg), markers)
|
9
|
-
end
|
10
|
-
|
11
|
-
def node(arg, markers = {})
|
12
|
-
return arg if arg.is_a?(Node)
|
13
|
-
unless looks_a_node?(arg)
|
14
|
-
raise ArgumentError, "Array expected, #{arg.inspect} found."
|
15
|
-
end
|
16
|
-
extend_node(arg, markers).tap do |node|
|
17
|
-
node.children.each{|c| node(c) if looks_a_node?(c)}
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
private
|
22
|
-
|
23
|
-
def looks_a_node?(arg)
|
24
|
-
arg.is_a?(Node) or (arg.is_a?(Array) and arg.first.is_a?(Symbol))
|
25
|
-
end
|
26
|
-
|
27
|
-
def extend_node(arg, markers)
|
28
|
-
mod = ast_module(arg)
|
29
|
-
arg.extend(mod).tap do |node|
|
30
|
-
node.markers = markers
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def ast_module(node)
|
35
|
-
modname = Language.rule2mod(node.first)
|
36
|
-
AST.const_get(modname) rescue Node
|
37
|
-
end
|
38
|
-
|
39
|
-
extend(self)
|
40
|
-
end # module Helpers
|
41
|
-
end # module AST
|
42
|
-
end # module Language
|
43
|
-
end # module Gisele
|
@@ -1,19 +0,0 @@
|
|
1
|
-
task_def:
|
2
|
-
shape: circle
|
3
|
-
style: filled
|
4
|
-
fillcolor: black
|
5
|
-
fixed: true
|
6
|
-
width: 0.1
|
7
|
-
task_call_st:
|
8
|
-
shape: box
|
9
|
-
while_st:
|
10
|
-
shape: diamond
|
11
|
-
if_st:
|
12
|
-
shape: diamond
|
13
|
-
case_st:
|
14
|
-
shape: diamond
|
15
|
-
par_st:
|
16
|
-
shape: box
|
17
|
-
height: 0.1
|
18
|
-
style: filled
|
19
|
-
fillcolor: black
|
@@ -1,146 +0,0 @@
|
|
1
|
-
module Gisele
|
2
|
-
module Language
|
3
|
-
class ToGraph < Rewriter
|
4
|
-
module Connector; end
|
5
|
-
|
6
|
-
def on_unit_def(node)
|
7
|
-
node.
|
8
|
-
children.
|
9
|
-
select{|n| n.first == :task_def}.
|
10
|
-
map{|taskdef| call(taskdef) }
|
11
|
-
end
|
12
|
-
|
13
|
-
def on_task_def(node)
|
14
|
-
@graph = Yargi::Digraph.new
|
15
|
-
|
16
|
-
entry, exit = add_vertex(node), add_vertex(node)
|
17
|
-
|
18
|
-
# flatten all elsif
|
19
|
-
c_entry, c_exit = call(ElsifFlattener.new.call(node.last))
|
20
|
-
connect(entry, c_entry)
|
21
|
-
connect(c_exit, exit)
|
22
|
-
|
23
|
-
@graph.vertices(Connector).each do |vertex|
|
24
|
-
next unless vertex.out_edges.size == 1
|
25
|
-
target = vertex.out_edges.first.target
|
26
|
-
@graph.reconnect(vertex.in_edges, nil, target)
|
27
|
-
@graph.remove_vertex(vertex)
|
28
|
-
end
|
29
|
-
|
30
|
-
@graph
|
31
|
-
end
|
32
|
-
|
33
|
-
def on_seq_st(node)
|
34
|
-
mine = entry_and_exit(node)
|
35
|
-
current = mine.first
|
36
|
-
node.children.each do |child|
|
37
|
-
c_entry, c_exit = call(child)
|
38
|
-
connect(current, c_entry)
|
39
|
-
current = c_exit
|
40
|
-
end
|
41
|
-
connect(current, mine.last)
|
42
|
-
mine
|
43
|
-
end
|
44
|
-
|
45
|
-
def on_par_st(node)
|
46
|
-
entry, exit = add_vertex(node), add_vertex(node)
|
47
|
-
node.children.each do |child|
|
48
|
-
c_entry, c_exit = call(child)
|
49
|
-
connect(entry, c_entry)
|
50
|
-
connect(c_exit, exit)
|
51
|
-
end
|
52
|
-
[entry, exit]
|
53
|
-
end
|
54
|
-
|
55
|
-
def on_if_st(node)
|
56
|
-
cond, then_clause, else_clause, = node.children
|
57
|
-
|
58
|
-
entry, exit = entry_and_exit(node)
|
59
|
-
|
60
|
-
diamond = add_vertex(node)
|
61
|
-
connect(entry, diamond)
|
62
|
-
|
63
|
-
c_entry, c_exit = call(then_clause)
|
64
|
-
connect(diamond, c_entry, true_ast_node)
|
65
|
-
connect(c_exit, exit)
|
66
|
-
|
67
|
-
if else_clause
|
68
|
-
c_entry, c_exit = call(else_clause.last)
|
69
|
-
connect(diamond, c_entry, false_ast_node)
|
70
|
-
connect(c_exit, exit)
|
71
|
-
else
|
72
|
-
connect(diamond, exit, false_ast_node)
|
73
|
-
end
|
74
|
-
|
75
|
-
[entry, exit]
|
76
|
-
end
|
77
|
-
|
78
|
-
def on_case_st(node)
|
79
|
-
cond, *clauses = node.children
|
80
|
-
|
81
|
-
entry, exit = entry_and_exit(node)
|
82
|
-
|
83
|
-
diamond = add_vertex(node)
|
84
|
-
connect(entry, diamond)
|
85
|
-
|
86
|
-
clauses.each do |clause|
|
87
|
-
c_entry, c_exit = call(clause.last)
|
88
|
-
connect(diamond, c_entry, clause)
|
89
|
-
connect(c_exit, exit)
|
90
|
-
end
|
91
|
-
|
92
|
-
[entry, exit]
|
93
|
-
end
|
94
|
-
|
95
|
-
|
96
|
-
def on_while_st(node)
|
97
|
-
cond, dost, = node.children
|
98
|
-
|
99
|
-
entry, exit = entry_and_exit(node)
|
100
|
-
|
101
|
-
diamond = add_vertex(node)
|
102
|
-
connect(entry, diamond)
|
103
|
-
|
104
|
-
c_entry, c_exit = call(node.last)
|
105
|
-
|
106
|
-
connect(diamond, exit, false_ast_node)
|
107
|
-
connect(diamond, c_entry, true_ast_node)
|
108
|
-
connect(c_exit, diamond)
|
109
|
-
|
110
|
-
[entry, exit]
|
111
|
-
end
|
112
|
-
|
113
|
-
def on_task_call_st(node)
|
114
|
-
entry, exit = entry_and_exit(node)
|
115
|
-
task = add_vertex(node)
|
116
|
-
connect(entry, task)
|
117
|
-
connect(task, exit)
|
118
|
-
[entry, exit]
|
119
|
-
end
|
120
|
-
|
121
|
-
private
|
122
|
-
|
123
|
-
def add_vertex(node)
|
124
|
-
@graph.add_vertex(node.dot_attributes)
|
125
|
-
end
|
126
|
-
|
127
|
-
def entry_and_exit(node, tag = Connector)
|
128
|
-
@graph.add_n_vertices(2, tag)
|
129
|
-
end
|
130
|
-
|
131
|
-
def connect(source, target, node = nil)
|
132
|
-
marks = node.nil? ? {} : node.dot_attributes
|
133
|
-
@graph.connect(source, target, marks)
|
134
|
-
end
|
135
|
-
|
136
|
-
def false_ast_node
|
137
|
-
Syntax.ast("false", :root => :bool_expr)
|
138
|
-
end
|
139
|
-
|
140
|
-
def true_ast_node
|
141
|
-
Syntax.ast("true", :root => :bool_expr)
|
142
|
-
end
|
143
|
-
|
144
|
-
end # class SugarRemoval
|
145
|
-
end # module Language
|
146
|
-
end # module Gisele
|
@@ -1,60 +0,0 @@
|
|
1
|
-
module Gisele
|
2
|
-
module Language
|
3
|
-
class Rewriter
|
4
|
-
include AST::Helpers
|
5
|
-
|
6
|
-
### class methods
|
7
|
-
|
8
|
-
def self.helpers
|
9
|
-
@helpers ||= [ WorkOnNodes.new ]
|
10
|
-
end
|
11
|
-
|
12
|
-
def self.add_helper(helper)
|
13
|
-
unless helpers.empty?
|
14
|
-
helpers.last.next_in_chain = helper
|
15
|
-
end
|
16
|
-
helpers << helper
|
17
|
-
end
|
18
|
-
|
19
|
-
### instance methods
|
20
|
-
|
21
|
-
attr_reader :mainflow
|
22
|
-
|
23
|
-
def initialize(options = {})
|
24
|
-
@options = options
|
25
|
-
@mainflow = options[:mainflow] || self
|
26
|
-
end
|
27
|
-
|
28
|
-
def call(node)
|
29
|
-
help(node) do |n|
|
30
|
-
meth = :"on_#{node.first}"
|
31
|
-
meth = :"on_missing" unless respond_to?(meth)
|
32
|
-
send(meth, node)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def on_missing(node)
|
37
|
-
raise UnexpectedNodeError, "Unexpected node: #{node.inspect}"
|
38
|
-
end
|
39
|
-
|
40
|
-
def copy_and_applyall(node)
|
41
|
-
node.copy do |memo,child|
|
42
|
-
memo << (child.is_a?(AST::Node) ? call(child) : child)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
private
|
47
|
-
|
48
|
-
def help(node)
|
49
|
-
@first_helper ||= self.class.helpers.first
|
50
|
-
@first_helper.call(self, node) do |_,n|
|
51
|
-
yield(n)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
end # class Rewriter
|
56
|
-
end # module Language
|
57
|
-
end # module Gisele
|
58
|
-
require_relative 'rewriter/helper'
|
59
|
-
require_relative 'rewriter/work_on_nodes'
|
60
|
-
require_relative 'rewriter/scoping'
|
@@ -1,41 +0,0 @@
|
|
1
|
-
module Gisele
|
2
|
-
module Language
|
3
|
-
class Rewriter
|
4
|
-
class Helper
|
5
|
-
|
6
|
-
attr_accessor :next_in_chain
|
7
|
-
|
8
|
-
def self.install_on(rewriter)
|
9
|
-
methods = const_get(:Methods)
|
10
|
-
rewriter.module_eval do
|
11
|
-
include methods
|
12
|
-
end
|
13
|
-
rewriter.add_helper(new)
|
14
|
-
end
|
15
|
-
|
16
|
-
def call(rw, node, &bl)
|
17
|
-
meth = :"on_#{node.first}"
|
18
|
-
meth = :"on_missing" unless respond_to?(meth)
|
19
|
-
send(meth, rw, node) do |r,n|
|
20
|
-
next_call(r, n, bl)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def on_missing(rw, node)
|
25
|
-
yield(rw, node)
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
|
30
|
-
def next_call(rw, node, toplevel)
|
31
|
-
if nic = next_in_chain
|
32
|
-
nic.call(rw, node, &toplevel)
|
33
|
-
else
|
34
|
-
toplevel.call(rw, node)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
end # class Helper
|
39
|
-
end # class Rewriter
|
40
|
-
end # module Language
|
41
|
-
end # module Gisele
|
@@ -1,34 +0,0 @@
|
|
1
|
-
module Gisele
|
2
|
-
module Language
|
3
|
-
class Rewriter
|
4
|
-
class Scoping < Helper
|
5
|
-
|
6
|
-
module Methods
|
7
|
-
|
8
|
-
def scope_stack
|
9
|
-
@scope_stack ||= []
|
10
|
-
end
|
11
|
-
|
12
|
-
def with_scope(scope)
|
13
|
-
scope_stack.push(scope)
|
14
|
-
result = yield
|
15
|
-
scope_stack.pop
|
16
|
-
result
|
17
|
-
end
|
18
|
-
|
19
|
-
end # module Methods
|
20
|
-
|
21
|
-
def on_missing(rw, node)
|
22
|
-
if node.rule_name.to_s =~ /_def/
|
23
|
-
rw.with_scope(node) do
|
24
|
-
yield(rw, node)
|
25
|
-
end
|
26
|
-
else
|
27
|
-
yield(rw, node)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
end # module Scoping
|
32
|
-
end # class Rewriter
|
33
|
-
end # module Language
|
34
|
-
end # module Gisele
|
@@ -1,30 +0,0 @@
|
|
1
|
-
module Gisele
|
2
|
-
module Language
|
3
|
-
class Rewriter
|
4
|
-
class WorkOnNodes < Helper
|
5
|
-
include AST::Helpers
|
6
|
-
|
7
|
-
def call(rw, node, &bl)
|
8
|
-
node = pre_call(node)
|
9
|
-
tran = next_call(rw, node, bl)
|
10
|
-
post_call(tran)
|
11
|
-
end
|
12
|
-
|
13
|
-
protected
|
14
|
-
|
15
|
-
def pre_call(node)
|
16
|
-
unless looks_a_node?(node)
|
17
|
-
msg = "AST node expected, got #{node.inspect}"
|
18
|
-
raise ArgumentError, msg, caller
|
19
|
-
end
|
20
|
-
node(node)
|
21
|
-
end
|
22
|
-
|
23
|
-
def post_call(t)
|
24
|
-
looks_a_node?(t) ? node(t) : t
|
25
|
-
end
|
26
|
-
|
27
|
-
end # module WorkOnNodes
|
28
|
-
end # class Rewriter
|
29
|
-
end # module Language
|
30
|
-
end # module Gisele
|
@@ -1,29 +0,0 @@
|
|
1
|
-
require_relative 'syntax/node'
|
2
|
-
module Gisele
|
3
|
-
module Language
|
4
|
-
module Syntax
|
5
|
-
Citrus.load(File.expand_path('../grammar', __FILE__))
|
6
|
-
|
7
|
-
def parse(input, options = {})
|
8
|
-
source = parsing_source(input)
|
9
|
-
Grammar.parse(source, options)
|
10
|
-
end
|
11
|
-
module_function :parse
|
12
|
-
|
13
|
-
def ast(input, parse_options = {})
|
14
|
-
parse(input, parse_options).to_ast
|
15
|
-
end
|
16
|
-
module_function :ast
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
def parsing_source(input)
|
21
|
-
input = File.read(input.to_path) if input.respond_to?(:to_path)
|
22
|
-
input = input.to_str if input.respond_to?(:to_str)
|
23
|
-
input
|
24
|
-
end
|
25
|
-
module_function :parsing_source
|
26
|
-
|
27
|
-
end # module Syntax
|
28
|
-
end # module Language
|
29
|
-
end # module Gisele
|
@@ -1,82 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
module Gisele::Language::AST
|
3
|
-
describe Node do
|
4
|
-
|
5
|
-
describe 'rule_name' do
|
6
|
-
it 'returns the first array element' do
|
7
|
-
node([:hello]).rule_name.should eq(:hello)
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
describe 'children' do
|
12
|
-
|
13
|
-
it 'returns all but the rule name' do
|
14
|
-
node([:hello, "world", "!"]).children.should eq(["world", "!"])
|
15
|
-
end
|
16
|
-
|
17
|
-
it 'returns an empty array when no children' do
|
18
|
-
node([:hello]).children.should eq([])
|
19
|
-
end
|
20
|
-
|
21
|
-
end # children
|
22
|
-
|
23
|
-
describe 'markers' do
|
24
|
-
|
25
|
-
it 'defaults to an empty hash' do
|
26
|
-
node([:hello]).markers.should eq({})
|
27
|
-
end
|
28
|
-
|
29
|
-
end # markers
|
30
|
-
|
31
|
-
describe 'copy' do
|
32
|
-
|
33
|
-
it 'collects block results ala `inject`' do
|
34
|
-
source = node([:unit_def, "world", "gisele"])
|
35
|
-
target = source.copy do |memo,child|
|
36
|
-
memo << child.upcase
|
37
|
-
end
|
38
|
-
target.should be_a(UnitDef)
|
39
|
-
target.should eq([:unit_def, "WORLD", "GISELE"])
|
40
|
-
end
|
41
|
-
|
42
|
-
it 'returns a real equal copy when no children' do
|
43
|
-
source = node([:unit_def])
|
44
|
-
target = source.copy do |memo,child| end
|
45
|
-
target.should eq(source)
|
46
|
-
target.object_id.should_not eq(source.object_id)
|
47
|
-
target.should be_a(UnitDef)
|
48
|
-
end
|
49
|
-
|
50
|
-
it 'keeps the markers unchanged' do
|
51
|
-
node = node([:unit_def], {:hello => "World"})
|
52
|
-
copy = node.copy do |memo,child| end
|
53
|
-
copy.markers.should eq({:hello => "World"})
|
54
|
-
copy.markers.object_id.should_not eq(node.markers.object_id)
|
55
|
-
end
|
56
|
-
|
57
|
-
end
|
58
|
-
|
59
|
-
describe 'dup' do
|
60
|
-
|
61
|
-
it 'duplicates the underlying array' do
|
62
|
-
arr = [:unit_def, "etc."]
|
63
|
-
node(arr).dup.should eq(arr)
|
64
|
-
end
|
65
|
-
|
66
|
-
it 'ensures duplicated array is still a node' do
|
67
|
-
arr = [:unit_def, "etc."]
|
68
|
-
node(arr).dup.should be_a(UnitDef)
|
69
|
-
node(arr).dup.should be_a(Node)
|
70
|
-
end
|
71
|
-
|
72
|
-
it 'keeps the markers unchanged' do
|
73
|
-
node = node([:unit_def, "etc."], {:hello => "World"})
|
74
|
-
copy = node.dup
|
75
|
-
copy.markers.should eq({:hello => "World"})
|
76
|
-
copy.markers.object_id.should_not eq(node.markers.object_id)
|
77
|
-
end
|
78
|
-
|
79
|
-
end # dup
|
80
|
-
|
81
|
-
end
|
82
|
-
end
|