You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
251 lines
6.5 KiB
251 lines
6.5 KiB
4 months ago
|
#!/usr/bin/ruby
|
||
|
# encoding: utf-8
|
||
|
|
||
|
require 'spec'
|
||
|
require 'antlr3/template'
|
||
|
require 'antlr3/util'
|
||
|
|
||
|
include ANTLR3
|
||
|
MethodDescription = Struct.new( :name, :body, :arguments )
|
||
|
TEMPLATE_NAMES = %w( method class_definition attribute )
|
||
|
SAMPLE_GROUP_FILE = File.join(
|
||
|
File.dirname( __FILE__ ), 'sample-input', 'template-group'
|
||
|
)
|
||
|
|
||
|
describe Template::Context do
|
||
|
example "creating an empty context" do
|
||
|
context = Template::Context.new
|
||
|
context.instance_variables.should be_empty
|
||
|
end
|
||
|
|
||
|
example "creating a context with a variable map" do
|
||
|
context = Template::Context.new(
|
||
|
:a => 1, :b => 2
|
||
|
)
|
||
|
|
||
|
vars = context.instance_variables.map { | i | i.to_s }
|
||
|
vars.should include( '@a' )
|
||
|
vars.should include( '@b' )
|
||
|
|
||
|
context.instance_variable_get( '@a' ).should == 1
|
||
|
context.instance_variable_get( '@b' ).should == 2
|
||
|
end
|
||
|
|
||
|
example "fetching variable values from []" do
|
||
|
context = Template::Context.new(
|
||
|
:a => 1, :b => 2
|
||
|
)
|
||
|
|
||
|
context[ :a ].should == 1
|
||
|
context[ 'a' ].should == 1
|
||
|
context[ :b ].should == 2
|
||
|
context[ 'b' ].should == 2
|
||
|
end
|
||
|
|
||
|
example "defining variables with []=" do
|
||
|
context = Template::Context.new( :a => 3 )
|
||
|
context[ :a ] = 1
|
||
|
context[ 'b' ] = 2
|
||
|
|
||
|
context.instance_variable_get( '@a' ).should == 1
|
||
|
context.instance_variable_get( '@b' ).should == 2
|
||
|
end
|
||
|
|
||
|
example "using method missing to assign values" do
|
||
|
context = Template::Context.new( :a => 3 )
|
||
|
context.a = 1
|
||
|
context.b = 2
|
||
|
|
||
|
context.instance_variable_get( '@a' ).should == 1
|
||
|
context.instance_variable_get( '@b' ).should == 2
|
||
|
end
|
||
|
|
||
|
example "using method missing to get variable values" do
|
||
|
context = Template::Context.new( :a => 1, :b => 2)
|
||
|
|
||
|
context.a.should == 1
|
||
|
context.b.should == 2
|
||
|
end
|
||
|
|
||
|
end
|
||
|
|
||
|
|
||
|
shared_examples_for "template groups" do
|
||
|
include ANTLR3::Util
|
||
|
|
||
|
example "template definitions" do
|
||
|
templates = @group.templates
|
||
|
templates.should_not be_empty
|
||
|
templates.should equal @group::TEMPLATES
|
||
|
|
||
|
names = templates.keys
|
||
|
|
||
|
names.should have(3).things
|
||
|
for template_name in TEMPLATE_NAMES
|
||
|
names.should include template_name
|
||
|
template_class = templates[ template_name ]
|
||
|
template_class.should be_a_kind_of Class
|
||
|
template_class.superclass.should equal Template::Context
|
||
|
template_class.should be < @group # it should include the group module
|
||
|
end
|
||
|
end
|
||
|
|
||
|
example "template_defined?( name ) should verify whether a template is defined in a group" do
|
||
|
for name in TEMPLATE_NAMES
|
||
|
@group.template_defined?( name ).should be_true
|
||
|
@group.template_defined?( name.to_s ).should be_true
|
||
|
end
|
||
|
|
||
|
@group.template_defined?( :something_else ).should be_false
|
||
|
end
|
||
|
|
||
|
example "template method definitions" do
|
||
|
for name in TEMPLATE_NAMES
|
||
|
@group.should respond_to( name )
|
||
|
@group.should respond_to( "#{ name }!" )
|
||
|
if RUBY_VERSION =~ /^1\.9/
|
||
|
@group.private_instance_methods.should include name.to_sym
|
||
|
@group.private_instance_methods.should include :"#{ name }!"
|
||
|
else
|
||
|
@group.private_instance_methods.should include name.to_s
|
||
|
@group.private_instance_methods.should include "#{ name }!"
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
example "template method operation" do
|
||
|
value = @group.class_definition
|
||
|
value.should be_a_kind_of Template::Context
|
||
|
|
||
|
value = @group.class_definition!
|
||
|
value.should be_a_kind_of String
|
||
|
|
||
|
value = @group.attribute( :name => 'a' )
|
||
|
value.should be_a_kind_of Template::Context
|
||
|
end
|
||
|
end
|
||
|
|
||
|
describe Template::Group, "dynamic template definition" do
|
||
|
include ANTLR3::Util
|
||
|
|
||
|
before :each do
|
||
|
@group = Template::Group.new do
|
||
|
extend ANTLR3::Util
|
||
|
define_template( :class_definition, tidy( <<-'END'.chomp ) )
|
||
|
| class <%= @name %><% if @superclass %> < <%= @superclass %><% end %>
|
||
|
| % if @attributes
|
||
|
|
|
||
|
| % for attr, access in @attributes
|
||
|
| <%= attribute( :name => attr, :access => ( access || 'rw' ) ).to_s.chomp %>
|
||
|
| % end
|
||
|
| % end
|
||
|
| % if @methods
|
||
|
| % for method in ( @methods || [] )
|
||
|
| <%= method( method ) %>
|
||
|
| % end
|
||
|
| % end
|
||
|
| end
|
||
|
END
|
||
|
|
||
|
define_template( :attribute, tidy( <<-'END'.chomp ) )
|
||
|
| % case @access.to_s.downcase
|
||
|
| % when 'r'
|
||
|
| attr_reader :<%= @name %>
|
||
|
| % when 'w'
|
||
|
| attr_writer :<%= @name %>
|
||
|
| % else
|
||
|
| attr_accessor :<%= @name %>
|
||
|
| % end
|
||
|
END
|
||
|
|
||
|
define_template( :method, tidy( <<-'END'.chomp ) )
|
||
|
|
|
||
|
| def <%= @name %><% if @arguments and not @arguments.empty? %>( <%= @arguments.join( ', ' ) %> )<% end %>
|
||
|
| <%= @body.gsub( /^/, ' ' ) %>
|
||
|
| end
|
||
|
END
|
||
|
end
|
||
|
end
|
||
|
|
||
|
it_should_behave_like "template groups"
|
||
|
|
||
|
example "template object string rendering" do
|
||
|
attributes = [
|
||
|
%w( family ),
|
||
|
%w( name r )
|
||
|
]
|
||
|
|
||
|
methods = [
|
||
|
MethodDescription.new( 'eat', %q[puts( "ate %s %s" % [ number, @name ] )], %w( number ) ),
|
||
|
MethodDescription.new( :to_s, '@name.to_s.dup' )
|
||
|
]
|
||
|
|
||
|
vegetable = @group.class_definition(
|
||
|
:name => 'Vegetable',
|
||
|
:superclass => 'Food',
|
||
|
:attributes => attributes,
|
||
|
:methods => methods
|
||
|
)
|
||
|
|
||
|
vegetable.to_s.should == tidy( <<-END.chomp )
|
||
|
| class Vegetable < Food
|
||
|
|
|
||
|
| attr_accessor :family
|
||
|
| attr_reader :name
|
||
|
|
|
||
|
| def eat( number )
|
||
|
| puts( "ate %s %s" % [ number, @name ] )
|
||
|
| end
|
||
|
|
|
||
|
| def to_s
|
||
|
| @name.to_s.dup
|
||
|
| end
|
||
|
| end
|
||
|
END
|
||
|
end
|
||
|
end
|
||
|
|
||
|
describe Template::Group, "loading a template definition file" do
|
||
|
|
||
|
before :each do
|
||
|
@group = Template::Group.load( SAMPLE_GROUP_FILE )
|
||
|
end
|
||
|
|
||
|
it_should_behave_like "template groups"
|
||
|
|
||
|
example "template object string rendering" do
|
||
|
attributes = [
|
||
|
%w( family ),
|
||
|
%w( name r )
|
||
|
]
|
||
|
|
||
|
methods = [
|
||
|
MethodDescription.new( 'eat', %q[puts( "ate %s %s" % [ number, @name ] )], %w( number ) ),
|
||
|
MethodDescription.new( :to_s, '@name.to_s.dup' )
|
||
|
]
|
||
|
|
||
|
vegetable = @group.class_definition(
|
||
|
:name => 'Vegetable',
|
||
|
:superclass => 'Food',
|
||
|
:attributes => attributes,
|
||
|
:methods => methods
|
||
|
)
|
||
|
|
||
|
vegetable.to_s.should == tidy( <<-END.chomp )
|
||
|
| class Vegetable < Food
|
||
|
|
|
||
|
| attr_accessor :family
|
||
|
| attr_reader :name
|
||
|
|
|
||
|
| def eat( number )
|
||
|
| puts( "ate %s %s" % [ number, @name ] )
|
||
|
| end
|
||
|
|
|
||
|
| def to_s
|
||
|
| @name.to_s.dup
|
||
|
| end
|
||
|
| end
|
||
|
END
|
||
|
end
|
||
|
end
|