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

#!/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