antlr3 1.6.0 → 1.6.3
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +8 -0
- data/Manifest.txt +94 -0
- data/README.txt +1 -1
- data/Rakefile +58 -0
- data/bin/antlr4ruby +101 -7
- data/java/antlr-full-3.2.1.jar +0 -0
- data/lib/antlr3.rb +38 -10
- data/lib/antlr3/constants.rb +13 -5
- data/lib/antlr3/debug.rb +57 -57
- data/lib/antlr3/dfa.rb +138 -68
- data/lib/antlr3/dot.rb +32 -32
- data/lib/antlr3/error.rb +85 -78
- data/lib/antlr3/main.rb +191 -187
- data/lib/antlr3/profile.rb +71 -70
- data/lib/antlr3/recognizers.rb +261 -226
- data/lib/antlr3/streams.rb +85 -84
- data/lib/antlr3/streams/interactive.rb +20 -27
- data/lib/antlr3/streams/rewrite.rb +89 -89
- data/lib/antlr3/task.rb +42 -33
- data/lib/antlr3/template.rb +2 -2
- data/lib/antlr3/template/group-lexer.rb +1 -1
- data/lib/antlr3/token.rb +76 -68
- data/lib/antlr3/tree.rb +125 -121
- data/lib/antlr3/tree/visitor.rb +1 -1
- data/lib/antlr3/tree/wizard.rb +1 -1
- data/lib/antlr3/util.rb +32 -33
- data/lib/antlr3/version.rb +3 -3
- data/templates/Ruby.stg +1 -1
- data/test/unit/test-streams.rb +11 -10
- data/test/unit/test-template.rb +206 -204
- metadata +4 -2
data/lib/antlr3/tree/wizard.rb
CHANGED
data/lib/antlr3/util.rb
CHANGED
@@ -6,10 +6,10 @@ module Util
|
|
6
6
|
|
7
7
|
module_function
|
8
8
|
|
9
|
-
def snake_case(str)
|
10
|
-
str = str.to_s.gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
|
11
|
-
str.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
12
|
-
str.tr!("-", "_")
|
9
|
+
def snake_case( str )
|
10
|
+
str = str.to_s.gsub( /([A-Z]+)([A-Z][a-z])/,'\1_\2' )
|
11
|
+
str.gsub!( /([a-z\d])([A-Z])/,'\1_\2' )
|
12
|
+
str.tr!( "-", "_" )
|
13
13
|
str.downcase!
|
14
14
|
str
|
15
15
|
end
|
@@ -21,10 +21,10 @@ module_function
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def tidy( here_doc, flow = false )
|
24
|
-
here_doc.gsub!(/^ *\| ?/, '')
|
24
|
+
here_doc.gsub!( /^ *\| ?/, '' )
|
25
25
|
if flow
|
26
26
|
here_doc.strip!
|
27
|
-
here_doc.gsub!(/\s+/, ' ')
|
27
|
+
here_doc.gsub!( /\s+/, ' ' )
|
28
28
|
end
|
29
29
|
return here_doc
|
30
30
|
end
|
@@ -45,37 +45,37 @@ private
|
|
45
45
|
def shared_attribute( name, *additional_members )
|
46
46
|
attr_reader name
|
47
47
|
|
48
|
-
additional_writers = additional_members.inject('') do |src, attr|
|
49
|
-
src << "@#{attr} = value if @#{attr}\n"
|
48
|
+
additional_writers = additional_members.inject( '' ) do |src, attr|
|
49
|
+
src << "@#{ attr } = value if @#{ attr }\n"
|
50
50
|
end
|
51
51
|
|
52
|
-
file, line, = caller[1].split(':', 3)
|
53
|
-
class_eval(<<-END, file, line.to_i)
|
54
|
-
def #{name}= value
|
55
|
-
@#{name} = value
|
52
|
+
file, line, = caller[ 1 ].split( ':', 3 )
|
53
|
+
class_eval( <<-END, file, line.to_i )
|
54
|
+
def #{ name }= value
|
55
|
+
@#{ name } = value
|
56
56
|
|
57
57
|
each_delegate do |del|
|
58
|
-
del.#{name} = value
|
58
|
+
del.#{ name } = value
|
59
59
|
end
|
60
60
|
|
61
|
-
#{additional_writers}
|
61
|
+
#{ additional_writers }
|
62
62
|
end
|
63
63
|
END
|
64
64
|
end
|
65
65
|
|
66
66
|
def abstract( name, message = nil )
|
67
|
-
message ||= "abstract method -- #{self.class}::#{name} has not been implemented"
|
68
|
-
file, line, = caller[1].split(':', 3)
|
69
|
-
class_eval(<<-END, file, line.to_i)
|
70
|
-
def #{name}( * )
|
71
|
-
raise TypeError, #{message.to_s.inspect}
|
67
|
+
message ||= "abstract method -- #{ self.class }::#{ name } has not been implemented"
|
68
|
+
file, line, = caller[ 1 ].split( ':', 3 )
|
69
|
+
class_eval( <<-END, file, line.to_i )
|
70
|
+
def #{ name }( * )
|
71
|
+
raise TypeError, #{ message.to_s.inspect }
|
72
72
|
end
|
73
73
|
END
|
74
74
|
end
|
75
75
|
|
76
76
|
def alias_accessor( alias_name, attr_name )
|
77
77
|
alias_method( alias_name, attr_name )
|
78
|
-
alias_method( :"#{alias_name}=", :"#{attr_name}=" )
|
78
|
+
alias_method( :"#{ alias_name }=", :"#{ attr_name }=" )
|
79
79
|
end
|
80
80
|
|
81
81
|
end
|
@@ -91,8 +91,8 @@ class Integer
|
|
91
91
|
#
|
92
92
|
# CREDIT Florian Gross
|
93
93
|
|
94
|
-
def at_least(x)
|
95
|
-
(self >= x) ? self : x
|
94
|
+
def at_least( x )
|
95
|
+
( self >= x ) ? self : x
|
96
96
|
end
|
97
97
|
|
98
98
|
# Returns the greater of self or x.
|
@@ -102,8 +102,8 @@ class Integer
|
|
102
102
|
#
|
103
103
|
# CREDIT Florian Gross
|
104
104
|
|
105
|
-
def at_most(x)
|
106
|
-
(self <= x) ? self : x
|
105
|
+
def at_most( x )
|
106
|
+
( self <= x ) ? self : x
|
107
107
|
end
|
108
108
|
|
109
109
|
# Returns self if above the given lower bound, or
|
@@ -119,7 +119,7 @@ class Integer
|
|
119
119
|
#
|
120
120
|
# CREDIT Trans
|
121
121
|
|
122
|
-
def bound(lower, upper=nil)
|
122
|
+
def bound( lower, upper=nil )
|
123
123
|
return lower if self < lower
|
124
124
|
return self unless upper
|
125
125
|
return upper if self > upper
|
@@ -130,7 +130,7 @@ end
|
|
130
130
|
|
131
131
|
|
132
132
|
class Range
|
133
|
-
def covers?(range)
|
133
|
+
def covers?( range )
|
134
134
|
range.first >= first or return false
|
135
135
|
if exclude_end?
|
136
136
|
range.exclude_end? ? last >= range.last : last > range.last
|
@@ -139,17 +139,16 @@ class Range
|
|
139
139
|
end
|
140
140
|
end
|
141
141
|
|
142
|
-
def covered_by?(range)
|
143
|
-
range.covers?(self)
|
142
|
+
def covered_by?( range )
|
143
|
+
range.covers?( self )
|
144
144
|
end
|
145
145
|
|
146
|
-
def overlaps?(range)
|
147
|
-
range.include?(first) or include?(range.first)
|
146
|
+
def overlaps?( range )
|
147
|
+
range.include?( first ) or include?( range.first )
|
148
148
|
end
|
149
149
|
|
150
|
-
def disjoint?(range)
|
151
|
-
not overlaps?(range)
|
150
|
+
def disjoint?( range )
|
151
|
+
not overlaps?( range )
|
152
152
|
end
|
153
153
|
|
154
154
|
end
|
155
|
-
|
data/lib/antlr3/version.rb
CHANGED
@@ -11,7 +11,7 @@ module ANTLR3
|
|
11
11
|
ANTLR_MINOR_VERSION = 2
|
12
12
|
ANTLR_PATCH_VERSION = 1
|
13
13
|
ANTLR_VERSION = [ ANTLR_MAJOR_VERSION, ANTLR_MINOR_VERSION, ANTLR_PATCH_VERSION ].freeze
|
14
|
-
ANTLR_VERSION_STRING = ANTLR_VERSION.join('.')
|
14
|
+
ANTLR_VERSION_STRING = ANTLR_VERSION.join( '.' )
|
15
15
|
ANTLR_VERSION_STRING.chomp!( '.0' ) # versioning drops minor version at 0
|
16
16
|
ANTLR_VERSION_STRING.freeze
|
17
17
|
|
@@ -20,8 +20,8 @@ module ANTLR3
|
|
20
20
|
#
|
21
21
|
MAJOR_VERSION = 1
|
22
22
|
MINOR_VERSION = 6
|
23
|
-
PATCH_VERSION =
|
23
|
+
PATCH_VERSION = 3
|
24
24
|
VERSION = [ MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION ]
|
25
|
-
VERSION_STRING = VERSION.join('.').freeze
|
25
|
+
VERSION_STRING = VERSION.join( '.' ).freeze
|
26
26
|
|
27
27
|
end
|
data/templates/Ruby.stg
CHANGED
data/test/unit/test-streams.rb
CHANGED
@@ -10,7 +10,7 @@ include ANTLR3
|
|
10
10
|
|
11
11
|
class TestStringStream < Test::Unit::TestCase
|
12
12
|
def setup
|
13
|
-
@stream = StringStream.new("oh\nhey!\n")
|
13
|
+
@stream = StringStream.new( "oh\nhey!\n" )
|
14
14
|
end
|
15
15
|
|
16
16
|
def test_size
|
@@ -202,6 +202,7 @@ class TestFileStream < Test::Unit::TestCase
|
|
202
202
|
|
203
203
|
|
204
204
|
def test_no_encoding
|
205
|
+
|
205
206
|
path = File.join(File.dirname(__FILE__), 'sample-input/file-stream-1')
|
206
207
|
@stream = FileStream.new(path)
|
207
208
|
|
@@ -253,23 +254,23 @@ class TestCommonTokenStream < Test::Unit::TestCase
|
|
253
254
|
# vvvvvvvv tests vvvvvvvvv
|
254
255
|
def test_init
|
255
256
|
@source = MockSource.new
|
256
|
-
@stream = CommonTokenStream.new(@source)
|
257
|
+
@stream = CommonTokenStream.new( @source )
|
257
258
|
@stream.position.should == 0
|
258
259
|
end
|
259
260
|
|
260
261
|
def test_rebuild
|
261
262
|
@source1 = MockSource.new
|
262
263
|
@source2 = MockSource.new
|
263
|
-
@source2.tokens << new_token(10, :channel => ANTLR3::HIDDEN) << new_token(11)
|
264
|
-
@stream = CommonTokenStream.new(@source1)
|
264
|
+
@source2.tokens << new_token( 10, :channel => ANTLR3::HIDDEN ) << new_token( 11 )
|
265
|
+
@stream = CommonTokenStream.new( @source1 )
|
265
266
|
|
266
267
|
@stream.position.should == 0
|
267
|
-
@stream.tokens.should
|
268
|
+
@stream.tokens.length.should == 0
|
268
269
|
|
269
|
-
@stream.rebuild(@source2)
|
270
|
+
@stream.rebuild( @source2 )
|
270
271
|
@stream.token_source.should == @source2
|
271
272
|
@stream.position.should == 1
|
272
|
-
@stream.tokens.should have(2).things
|
273
|
+
@stream.tokens.should have( 2 ).things
|
273
274
|
end
|
274
275
|
|
275
276
|
def test_look_empty_source
|
@@ -326,7 +327,7 @@ class TestCommonTokenStream < Test::Unit::TestCase
|
|
326
327
|
@source = MockSource.new
|
327
328
|
@source.tokens << new_token(12) << new_token(13)
|
328
329
|
@stream = CommonTokenStream.new(@source)
|
329
|
-
@stream.look(0).should
|
330
|
+
@stream.look(0).should == nil
|
330
331
|
end
|
331
332
|
|
332
333
|
def test_lb_beyond_begin
|
@@ -337,9 +338,9 @@ class TestCommonTokenStream < Test::Unit::TestCase
|
|
337
338
|
new_token(13)
|
338
339
|
@stream = CommonTokenStream.new(@source)
|
339
340
|
|
340
|
-
@stream.look(-1).should
|
341
|
+
@stream.look(-1).should == nil
|
341
342
|
2.times { @stream.consume }
|
342
|
-
@stream.look(-3).should
|
343
|
+
@stream.look(-3).should == nil
|
343
344
|
end
|
344
345
|
|
345
346
|
def test_fill_buffer
|
data/test/unit/test-template.rb
CHANGED
@@ -12,237 +12,239 @@ SAMPLE_GROUP_FILE = File.join(
|
|
12
12
|
File.dirname( __FILE__ ), 'sample-input', 'template-group'
|
13
13
|
)
|
14
14
|
|
15
|
-
describe Template do
|
15
|
+
describe Template::Context do
|
16
|
+
example "creating an empty context" do
|
17
|
+
context = Template::Context.new
|
18
|
+
context.instance_variables.should be_empty
|
19
|
+
end
|
16
20
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
end
|
22
|
-
|
23
|
-
example "creating a context with a variable map" do
|
24
|
-
context = Template::Context.new(
|
25
|
-
:a => 1, :b => 2
|
26
|
-
)
|
27
|
-
|
28
|
-
vars = context.instance_variables.map { | i | i.to_s }
|
29
|
-
vars.should include( '@a' )
|
30
|
-
vars.should include( '@b' )
|
31
|
-
|
32
|
-
context.instance_variable_get( '@a' ).should == 1
|
33
|
-
context.instance_variable_get( '@b' ).should == 2
|
34
|
-
end
|
21
|
+
example "creating a context with a variable map" do
|
22
|
+
context = Template::Context.new(
|
23
|
+
:a => 1, :b => 2
|
24
|
+
)
|
35
25
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
)
|
40
|
-
|
41
|
-
context[ :a ].should == 1
|
42
|
-
context[ 'a' ].should == 1
|
43
|
-
context[ :b ].should == 2
|
44
|
-
context[ 'b' ].should == 2
|
45
|
-
end
|
26
|
+
vars = context.instance_variables.map { | i | i.to_s }
|
27
|
+
vars.should include( '@a' )
|
28
|
+
vars.should include( '@b' )
|
46
29
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
30
|
+
context.instance_variable_get( '@a' ).should == 1
|
31
|
+
context.instance_variable_get( '@b' ).should == 2
|
32
|
+
end
|
33
|
+
|
34
|
+
example "fetching variable values from []" do
|
35
|
+
context = Template::Context.new(
|
36
|
+
:a => 1, :b => 2
|
37
|
+
)
|
38
|
+
|
39
|
+
context[ :a ].should == 1
|
40
|
+
context[ 'a' ].should == 1
|
41
|
+
context[ :b ].should == 2
|
42
|
+
context[ 'b' ].should == 2
|
43
|
+
end
|
44
|
+
|
45
|
+
example "defining variables with []=" do
|
46
|
+
context = Template::Context.new( :a => 3 )
|
47
|
+
context[ :a ] = 1
|
48
|
+
context[ 'b' ] = 2
|
55
49
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
50
|
+
context.instance_variable_get( '@a' ).should == 1
|
51
|
+
context.instance_variable_get( '@b' ).should == 2
|
52
|
+
end
|
53
|
+
|
54
|
+
example "using method missing to assign values" do
|
55
|
+
context = Template::Context.new( :a => 3 )
|
56
|
+
context.a = 1
|
57
|
+
context.b = 2
|
64
58
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
59
|
+
context.instance_variable_get( '@a' ).should == 1
|
60
|
+
context.instance_variable_get( '@b' ).should == 2
|
61
|
+
end
|
62
|
+
|
63
|
+
example "using method missing to get variable values" do
|
64
|
+
context = Template::Context.new( :a => 1, :b => 2)
|
71
65
|
|
66
|
+
context.a.should == 1
|
67
|
+
context.b.should == 2
|
72
68
|
end
|
73
69
|
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
shared_examples_for "template groups" do
|
74
|
+
include ANTLR3::Util
|
74
75
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
template_class.should be_a_kind_of Class
|
90
|
-
template_class.superclass.should equal Template::Context
|
91
|
-
template_class.should be < @group # it should include the group module
|
92
|
-
end
|
76
|
+
example "template definitions" do
|
77
|
+
templates = @group.templates
|
78
|
+
templates.should_not be_empty
|
79
|
+
templates.should equal @group::TEMPLATES
|
80
|
+
|
81
|
+
names = templates.keys
|
82
|
+
|
83
|
+
names.should have(3).things
|
84
|
+
for template_name in TEMPLATE_NAMES
|
85
|
+
names.should include template_name
|
86
|
+
template_class = templates[ template_name ]
|
87
|
+
template_class.should be_a_kind_of Class
|
88
|
+
template_class.superclass.should equal Template::Context
|
89
|
+
template_class.should be < @group # it should include the group module
|
93
90
|
end
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
@group.template_defined?( :somethign_else ).should be_false
|
91
|
+
end
|
92
|
+
|
93
|
+
example "template_defined?( name ) should verify whether a template is defined in a group" do
|
94
|
+
for name in TEMPLATE_NAMES
|
95
|
+
@group.template_defined?( name ).should be_true
|
96
|
+
@group.template_defined?( name.to_s ).should be_true
|
102
97
|
end
|
103
98
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
99
|
+
@group.template_defined?( :something_else ).should be_false
|
100
|
+
end
|
101
|
+
|
102
|
+
example "template method definitions" do
|
103
|
+
for name in TEMPLATE_NAMES
|
104
|
+
@group.should respond_to( name )
|
105
|
+
@group.should respond_to( "#{ name }!" )
|
106
|
+
if RUBY_VERSION =~ /^1\.9/
|
107
|
+
@group.private_instance_methods.should include name.to_sym
|
108
|
+
@group.private_instance_methods.should include :"#{ name }!"
|
109
|
+
else
|
108
110
|
@group.private_instance_methods.should include name.to_s
|
109
111
|
@group.private_instance_methods.should include "#{ name }!"
|
110
112
|
end
|
111
113
|
end
|
112
|
-
|
113
|
-
example "template method operation" do
|
114
|
-
value = @group.class_definition
|
115
|
-
value.should be_a_kind_of Template::Context
|
116
|
-
|
117
|
-
value = @group.class_definition!
|
118
|
-
value.should be_a_kind_of String
|
119
|
-
|
120
|
-
value = @group.attribute( :name => 'a' )
|
121
|
-
value.should be_a_kind_of Template::Context
|
122
|
-
end
|
123
114
|
end
|
124
115
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
before :each do
|
129
|
-
@group = Template::Group.new do
|
130
|
-
extend ANTLR3::Util
|
131
|
-
define_template( :class_definition, tidy( <<-'END'.chomp ) )
|
132
|
-
| class <%= @name %><% if @superclass %> < <%= @superclass %><% end %>
|
133
|
-
| % if @attributes
|
134
|
-
|
|
135
|
-
| % for attr, access in @attributes
|
136
|
-
| <%= attribute( :name => attr, :access => ( access || 'rw' ) ).to_s.chomp %>
|
137
|
-
| % end
|
138
|
-
| % end
|
139
|
-
| % if @methods
|
140
|
-
| % for method in ( @methods || [] )
|
141
|
-
| <%= method( method ) %>
|
142
|
-
| % end
|
143
|
-
| % end
|
144
|
-
| end
|
145
|
-
END
|
146
|
-
|
147
|
-
define_template( :attribute, tidy( <<-'END'.chomp ) )
|
148
|
-
| % case @access.to_s.downcase
|
149
|
-
| % when 'r'
|
150
|
-
| attr_reader :<%= @name %>
|
151
|
-
| % when 'w'
|
152
|
-
| attr_writer :<%= @name %>
|
153
|
-
| % else
|
154
|
-
| attr_accessor :<%= @name %>
|
155
|
-
| % end
|
156
|
-
END
|
157
|
-
|
158
|
-
define_template( :method, tidy( <<-'END'.chomp ) )
|
159
|
-
|
|
160
|
-
| def <%= @name %><% if @arguments and not @arguments.empty? %>( <%= @arguments.join( ', ' ) %> )<% end %>
|
161
|
-
| <%= @body.gsub( /^/, ' ' ) %>
|
162
|
-
| end
|
163
|
-
END
|
164
|
-
end
|
165
|
-
end
|
116
|
+
example "template method operation" do
|
117
|
+
value = @group.class_definition
|
118
|
+
value.should be_a_kind_of Template::Context
|
166
119
|
|
167
|
-
|
120
|
+
value = @group.class_definition!
|
121
|
+
value.should be_a_kind_of String
|
168
122
|
|
169
|
-
|
170
|
-
|
171
|
-
%w( family ),
|
172
|
-
%w( name r )
|
173
|
-
]
|
174
|
-
|
175
|
-
methods = [
|
176
|
-
MethodDescription.new( 'eat', %q[puts( "ate %s %s" % [ number, @name ] )], %w( number ) ),
|
177
|
-
MethodDescription.new( :to_s, '@name.to_s.dup' )
|
178
|
-
]
|
179
|
-
|
180
|
-
vegetable = @group.class_definition(
|
181
|
-
:name => 'Vegetable',
|
182
|
-
:superclass => 'Food',
|
183
|
-
:attributes => attributes,
|
184
|
-
:methods => methods
|
185
|
-
)
|
186
|
-
|
187
|
-
vegetable.to_s.should == tidy( <<-END.chomp )
|
188
|
-
| class Vegetable < Food
|
189
|
-
|
|
190
|
-
| attr_accessor :family
|
191
|
-
| attr_reader :name
|
192
|
-
|
|
193
|
-
| def eat( number )
|
194
|
-
| puts( "ate %s %s" % [ number, @name ] )
|
195
|
-
| end
|
196
|
-
|
|
197
|
-
| def to_s
|
198
|
-
| @name.to_s.dup
|
199
|
-
| end
|
200
|
-
| end
|
201
|
-
END
|
202
|
-
end
|
123
|
+
value = @group.attribute( :name => 'a' )
|
124
|
+
value.should be_a_kind_of Template::Context
|
203
125
|
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe Template::Group, "dynamic template definition" do
|
129
|
+
include ANTLR3::Util
|
204
130
|
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
131
|
+
before :each do
|
132
|
+
@group = Template::Group.new do
|
133
|
+
extend ANTLR3::Util
|
134
|
+
define_template( :class_definition, tidy( <<-'END'.chomp ) )
|
135
|
+
| class <%= @name %><% if @superclass %> < <%= @superclass %><% end %>
|
136
|
+
| % if @attributes
|
137
|
+
|
|
138
|
+
| % for attr, access in @attributes
|
139
|
+
| <%= attribute( :name => attr, :access => ( access || 'rw' ) ).to_s.chomp %>
|
140
|
+
| % end
|
141
|
+
| % end
|
142
|
+
| % if @methods
|
143
|
+
| % for method in ( @methods || [] )
|
144
|
+
| <%= method( method ) %>
|
145
|
+
| % end
|
146
|
+
| % end
|
147
|
+
| end
|
148
|
+
END
|
222
149
|
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
150
|
+
define_template( :attribute, tidy( <<-'END'.chomp ) )
|
151
|
+
| % case @access.to_s.downcase
|
152
|
+
| % when 'r'
|
153
|
+
| attr_reader :<%= @name %>
|
154
|
+
| % when 'w'
|
155
|
+
| attr_writer :<%= @name %>
|
156
|
+
| % else
|
157
|
+
| attr_accessor :<%= @name %>
|
158
|
+
| % end
|
159
|
+
END
|
229
160
|
|
230
|
-
|
231
|
-
| class Vegetable < Food
|
232
|
-
|
|
233
|
-
| attr_accessor :family
|
234
|
-
| attr_reader :name
|
161
|
+
define_template( :method, tidy( <<-'END'.chomp ) )
|
235
162
|
|
|
236
|
-
| def
|
237
|
-
|
|
163
|
+
| def <%= @name %><% if @arguments and not @arguments.empty? %>( <%= @arguments.join( ', ' ) %> )<% end %>
|
164
|
+
| <%= @body.gsub( /^/, ' ' ) %>
|
238
165
|
| end
|
239
|
-
|
|
240
|
-
| def to_s
|
241
|
-
| @name.to_s.dup
|
242
|
-
| end
|
243
|
-
| end
|
244
166
|
END
|
245
167
|
end
|
246
|
-
|
247
168
|
end
|
169
|
+
|
170
|
+
it_should_behave_like "template groups"
|
171
|
+
|
172
|
+
example "template object string rendering" do
|
173
|
+
attributes = [
|
174
|
+
%w( family ),
|
175
|
+
%w( name r )
|
176
|
+
]
|
177
|
+
|
178
|
+
methods = [
|
179
|
+
MethodDescription.new( 'eat', %q[puts( "ate %s %s" % [ number, @name ] )], %w( number ) ),
|
180
|
+
MethodDescription.new( :to_s, '@name.to_s.dup' )
|
181
|
+
]
|
182
|
+
|
183
|
+
vegetable = @group.class_definition(
|
184
|
+
:name => 'Vegetable',
|
185
|
+
:superclass => 'Food',
|
186
|
+
:attributes => attributes,
|
187
|
+
:methods => methods
|
188
|
+
)
|
189
|
+
|
190
|
+
vegetable.to_s.should == tidy( <<-END.chomp )
|
191
|
+
| class Vegetable < Food
|
192
|
+
|
|
193
|
+
| attr_accessor :family
|
194
|
+
| attr_reader :name
|
195
|
+
|
|
196
|
+
| def eat( number )
|
197
|
+
| puts( "ate %s %s" % [ number, @name ] )
|
198
|
+
| end
|
199
|
+
|
|
200
|
+
| def to_s
|
201
|
+
| @name.to_s.dup
|
202
|
+
| end
|
203
|
+
| end
|
204
|
+
END
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
describe Template::Group, "loading a template definition file" do
|
209
|
+
before :each do
|
210
|
+
@group = Template::Group.load( SAMPLE_GROUP_FILE )
|
211
|
+
end
|
212
|
+
|
213
|
+
it_should_behave_like "template groups"
|
214
|
+
|
215
|
+
example "template object string rendering" do
|
216
|
+
attributes = [
|
217
|
+
%w( family ),
|
218
|
+
%w( name r )
|
219
|
+
]
|
220
|
+
|
221
|
+
methods = [
|
222
|
+
MethodDescription.new( 'eat', %q[puts( "ate %s %s" % [ number, @name ] )], %w( number ) ),
|
223
|
+
MethodDescription.new( :to_s, '@name.to_s.dup' )
|
224
|
+
]
|
225
|
+
|
226
|
+
vegetable = @group.class_definition(
|
227
|
+
:name => 'Vegetable',
|
228
|
+
:superclass => 'Food',
|
229
|
+
:attributes => attributes,
|
230
|
+
:methods => methods
|
231
|
+
)
|
232
|
+
|
233
|
+
vegetable.to_s.should == tidy( <<-END.chomp )
|
234
|
+
| class Vegetable < Food
|
235
|
+
|
|
236
|
+
| attr_accessor :family
|
237
|
+
| attr_reader :name
|
238
|
+
|
|
239
|
+
| def eat( number )
|
240
|
+
| puts( "ate %s %s" % [ number, @name ] )
|
241
|
+
| end
|
242
|
+
|
|
243
|
+
| def to_s
|
244
|
+
| @name.to_s.dup
|
245
|
+
| end
|
246
|
+
| end
|
247
|
+
END
|
248
|
+
end
|
249
|
+
|
248
250
|
end
|