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