1*16467b97STreehugger Robot#!/usr/bin/ruby 2*16467b97STreehugger Robot# encoding: utf-8 3*16467b97STreehugger Robot 4*16467b97STreehugger Robotrequire 'spec' 5*16467b97STreehugger Robotrequire 'antlr3/template' 6*16467b97STreehugger Robotrequire 'antlr3/util' 7*16467b97STreehugger Robot 8*16467b97STreehugger Robotinclude ANTLR3 9*16467b97STreehugger RobotMethodDescription = Struct.new( :name, :body, :arguments ) 10*16467b97STreehugger RobotTEMPLATE_NAMES = %w( method class_definition attribute ) 11*16467b97STreehugger RobotSAMPLE_GROUP_FILE = File.join( 12*16467b97STreehugger Robot File.dirname( __FILE__ ), 'sample-input', 'template-group' 13*16467b97STreehugger Robot) 14*16467b97STreehugger Robot 15*16467b97STreehugger Robotdescribe Template::Context do 16*16467b97STreehugger Robot example "creating an empty context" do 17*16467b97STreehugger Robot context = Template::Context.new 18*16467b97STreehugger Robot context.instance_variables.should be_empty 19*16467b97STreehugger Robot end 20*16467b97STreehugger Robot 21*16467b97STreehugger Robot example "creating a context with a variable map" do 22*16467b97STreehugger Robot context = Template::Context.new( 23*16467b97STreehugger Robot :a => 1, :b => 2 24*16467b97STreehugger Robot ) 25*16467b97STreehugger Robot 26*16467b97STreehugger Robot vars = context.instance_variables.map { | i | i.to_s } 27*16467b97STreehugger Robot vars.should include( '@a' ) 28*16467b97STreehugger Robot vars.should include( '@b' ) 29*16467b97STreehugger Robot 30*16467b97STreehugger Robot context.instance_variable_get( '@a' ).should == 1 31*16467b97STreehugger Robot context.instance_variable_get( '@b' ).should == 2 32*16467b97STreehugger Robot end 33*16467b97STreehugger Robot 34*16467b97STreehugger Robot example "fetching variable values from []" do 35*16467b97STreehugger Robot context = Template::Context.new( 36*16467b97STreehugger Robot :a => 1, :b => 2 37*16467b97STreehugger Robot ) 38*16467b97STreehugger Robot 39*16467b97STreehugger Robot context[ :a ].should == 1 40*16467b97STreehugger Robot context[ 'a' ].should == 1 41*16467b97STreehugger Robot context[ :b ].should == 2 42*16467b97STreehugger Robot context[ 'b' ].should == 2 43*16467b97STreehugger Robot end 44*16467b97STreehugger Robot 45*16467b97STreehugger Robot example "defining variables with []=" do 46*16467b97STreehugger Robot context = Template::Context.new( :a => 3 ) 47*16467b97STreehugger Robot context[ :a ] = 1 48*16467b97STreehugger Robot context[ 'b' ] = 2 49*16467b97STreehugger Robot 50*16467b97STreehugger Robot context.instance_variable_get( '@a' ).should == 1 51*16467b97STreehugger Robot context.instance_variable_get( '@b' ).should == 2 52*16467b97STreehugger Robot end 53*16467b97STreehugger Robot 54*16467b97STreehugger Robot example "using method missing to assign values" do 55*16467b97STreehugger Robot context = Template::Context.new( :a => 3 ) 56*16467b97STreehugger Robot context.a = 1 57*16467b97STreehugger Robot context.b = 2 58*16467b97STreehugger Robot 59*16467b97STreehugger Robot context.instance_variable_get( '@a' ).should == 1 60*16467b97STreehugger Robot context.instance_variable_get( '@b' ).should == 2 61*16467b97STreehugger Robot end 62*16467b97STreehugger Robot 63*16467b97STreehugger Robot example "using method missing to get variable values" do 64*16467b97STreehugger Robot context = Template::Context.new( :a => 1, :b => 2) 65*16467b97STreehugger Robot 66*16467b97STreehugger Robot context.a.should == 1 67*16467b97STreehugger Robot context.b.should == 2 68*16467b97STreehugger Robot end 69*16467b97STreehugger Robot 70*16467b97STreehugger Robotend 71*16467b97STreehugger Robot 72*16467b97STreehugger Robot 73*16467b97STreehugger Robotshared_examples_for "template groups" do 74*16467b97STreehugger Robot include ANTLR3::Util 75*16467b97STreehugger Robot 76*16467b97STreehugger Robot example "template definitions" do 77*16467b97STreehugger Robot templates = @group.templates 78*16467b97STreehugger Robot templates.should_not be_empty 79*16467b97STreehugger Robot templates.should equal @group::TEMPLATES 80*16467b97STreehugger Robot 81*16467b97STreehugger Robot names = templates.keys 82*16467b97STreehugger Robot 83*16467b97STreehugger Robot names.should have(3).things 84*16467b97STreehugger Robot for template_name in TEMPLATE_NAMES 85*16467b97STreehugger Robot names.should include template_name 86*16467b97STreehugger Robot template_class = templates[ template_name ] 87*16467b97STreehugger Robot template_class.should be_a_kind_of Class 88*16467b97STreehugger Robot template_class.superclass.should equal Template::Context 89*16467b97STreehugger Robot template_class.should be < @group # it should include the group module 90*16467b97STreehugger Robot end 91*16467b97STreehugger Robot end 92*16467b97STreehugger Robot 93*16467b97STreehugger Robot example "template_defined?( name ) should verify whether a template is defined in a group" do 94*16467b97STreehugger Robot for name in TEMPLATE_NAMES 95*16467b97STreehugger Robot @group.template_defined?( name ).should be_true 96*16467b97STreehugger Robot @group.template_defined?( name.to_s ).should be_true 97*16467b97STreehugger Robot end 98*16467b97STreehugger Robot 99*16467b97STreehugger Robot @group.template_defined?( :something_else ).should be_false 100*16467b97STreehugger Robot end 101*16467b97STreehugger Robot 102*16467b97STreehugger Robot example "template method definitions" do 103*16467b97STreehugger Robot for name in TEMPLATE_NAMES 104*16467b97STreehugger Robot @group.should respond_to( name ) 105*16467b97STreehugger Robot @group.should respond_to( "#{ name }!" ) 106*16467b97STreehugger Robot if RUBY_VERSION =~ /^1\.9/ 107*16467b97STreehugger Robot @group.private_instance_methods.should include name.to_sym 108*16467b97STreehugger Robot @group.private_instance_methods.should include :"#{ name }!" 109*16467b97STreehugger Robot else 110*16467b97STreehugger Robot @group.private_instance_methods.should include name.to_s 111*16467b97STreehugger Robot @group.private_instance_methods.should include "#{ name }!" 112*16467b97STreehugger Robot end 113*16467b97STreehugger Robot end 114*16467b97STreehugger Robot end 115*16467b97STreehugger Robot 116*16467b97STreehugger Robot example "template method operation" do 117*16467b97STreehugger Robot value = @group.class_definition 118*16467b97STreehugger Robot value.should be_a_kind_of Template::Context 119*16467b97STreehugger Robot 120*16467b97STreehugger Robot value = @group.class_definition! 121*16467b97STreehugger Robot value.should be_a_kind_of String 122*16467b97STreehugger Robot 123*16467b97STreehugger Robot value = @group.attribute( :name => 'a' ) 124*16467b97STreehugger Robot value.should be_a_kind_of Template::Context 125*16467b97STreehugger Robot end 126*16467b97STreehugger Robotend 127*16467b97STreehugger Robot 128*16467b97STreehugger Robotdescribe Template::Group, "dynamic template definition" do 129*16467b97STreehugger Robot include ANTLR3::Util 130*16467b97STreehugger Robot 131*16467b97STreehugger Robot before :each do 132*16467b97STreehugger Robot @group = Template::Group.new do 133*16467b97STreehugger Robot extend ANTLR3::Util 134*16467b97STreehugger Robot define_template( :class_definition, tidy( <<-'END'.chomp ) ) 135*16467b97STreehugger Robot | class <%= @name %><% if @superclass %> < <%= @superclass %><% end %> 136*16467b97STreehugger Robot | % if @attributes 137*16467b97STreehugger Robot | 138*16467b97STreehugger Robot | % for attr, access in @attributes 139*16467b97STreehugger Robot | <%= attribute( :name => attr, :access => ( access || 'rw' ) ).to_s.chomp %> 140*16467b97STreehugger Robot | % end 141*16467b97STreehugger Robot | % end 142*16467b97STreehugger Robot | % if @methods 143*16467b97STreehugger Robot | % for method in ( @methods || [] ) 144*16467b97STreehugger Robot | <%= method( method ) %> 145*16467b97STreehugger Robot | % end 146*16467b97STreehugger Robot | % end 147*16467b97STreehugger Robot | end 148*16467b97STreehugger Robot END 149*16467b97STreehugger Robot 150*16467b97STreehugger Robot define_template( :attribute, tidy( <<-'END'.chomp ) ) 151*16467b97STreehugger Robot | % case @access.to_s.downcase 152*16467b97STreehugger Robot | % when 'r' 153*16467b97STreehugger Robot | attr_reader :<%= @name %> 154*16467b97STreehugger Robot | % when 'w' 155*16467b97STreehugger Robot | attr_writer :<%= @name %> 156*16467b97STreehugger Robot | % else 157*16467b97STreehugger Robot | attr_accessor :<%= @name %> 158*16467b97STreehugger Robot | % end 159*16467b97STreehugger Robot END 160*16467b97STreehugger Robot 161*16467b97STreehugger Robot define_template( :method, tidy( <<-'END'.chomp ) ) 162*16467b97STreehugger Robot | 163*16467b97STreehugger Robot | def <%= @name %><% if @arguments and not @arguments.empty? %>( <%= @arguments.join( ', ' ) %> )<% end %> 164*16467b97STreehugger Robot | <%= @body.gsub( /^/, ' ' ) %> 165*16467b97STreehugger Robot | end 166*16467b97STreehugger Robot END 167*16467b97STreehugger Robot end 168*16467b97STreehugger Robot end 169*16467b97STreehugger Robot 170*16467b97STreehugger Robot it_should_behave_like "template groups" 171*16467b97STreehugger Robot 172*16467b97STreehugger Robot example "template object string rendering" do 173*16467b97STreehugger Robot attributes = [ 174*16467b97STreehugger Robot %w( family ), 175*16467b97STreehugger Robot %w( name r ) 176*16467b97STreehugger Robot ] 177*16467b97STreehugger Robot 178*16467b97STreehugger Robot methods = [ 179*16467b97STreehugger Robot MethodDescription.new( 'eat', %q[puts( "ate %s %s" % [ number, @name ] )], %w( number ) ), 180*16467b97STreehugger Robot MethodDescription.new( :to_s, '@name.to_s.dup' ) 181*16467b97STreehugger Robot ] 182*16467b97STreehugger Robot 183*16467b97STreehugger Robot vegetable = @group.class_definition( 184*16467b97STreehugger Robot :name => 'Vegetable', 185*16467b97STreehugger Robot :superclass => 'Food', 186*16467b97STreehugger Robot :attributes => attributes, 187*16467b97STreehugger Robot :methods => methods 188*16467b97STreehugger Robot ) 189*16467b97STreehugger Robot 190*16467b97STreehugger Robot vegetable.to_s.should == tidy( <<-END.chomp ) 191*16467b97STreehugger Robot | class Vegetable < Food 192*16467b97STreehugger Robot | 193*16467b97STreehugger Robot | attr_accessor :family 194*16467b97STreehugger Robot | attr_reader :name 195*16467b97STreehugger Robot | 196*16467b97STreehugger Robot | def eat( number ) 197*16467b97STreehugger Robot | puts( "ate %s %s" % [ number, @name ] ) 198*16467b97STreehugger Robot | end 199*16467b97STreehugger Robot | 200*16467b97STreehugger Robot | def to_s 201*16467b97STreehugger Robot | @name.to_s.dup 202*16467b97STreehugger Robot | end 203*16467b97STreehugger Robot | end 204*16467b97STreehugger Robot END 205*16467b97STreehugger Robot end 206*16467b97STreehugger Robotend 207*16467b97STreehugger Robot 208*16467b97STreehugger Robotdescribe Template::Group, "loading a template definition file" do 209*16467b97STreehugger Robot 210*16467b97STreehugger Robot before :each do 211*16467b97STreehugger Robot @group = Template::Group.load( SAMPLE_GROUP_FILE ) 212*16467b97STreehugger Robot end 213*16467b97STreehugger Robot 214*16467b97STreehugger Robot it_should_behave_like "template groups" 215*16467b97STreehugger Robot 216*16467b97STreehugger Robot example "template object string rendering" do 217*16467b97STreehugger Robot attributes = [ 218*16467b97STreehugger Robot %w( family ), 219*16467b97STreehugger Robot %w( name r ) 220*16467b97STreehugger Robot ] 221*16467b97STreehugger Robot 222*16467b97STreehugger Robot methods = [ 223*16467b97STreehugger Robot MethodDescription.new( 'eat', %q[puts( "ate %s %s" % [ number, @name ] )], %w( number ) ), 224*16467b97STreehugger Robot MethodDescription.new( :to_s, '@name.to_s.dup' ) 225*16467b97STreehugger Robot ] 226*16467b97STreehugger Robot 227*16467b97STreehugger Robot vegetable = @group.class_definition( 228*16467b97STreehugger Robot :name => 'Vegetable', 229*16467b97STreehugger Robot :superclass => 'Food', 230*16467b97STreehugger Robot :attributes => attributes, 231*16467b97STreehugger Robot :methods => methods 232*16467b97STreehugger Robot ) 233*16467b97STreehugger Robot 234*16467b97STreehugger Robot vegetable.to_s.should == tidy( <<-END.chomp ) 235*16467b97STreehugger Robot | class Vegetable < Food 236*16467b97STreehugger Robot | 237*16467b97STreehugger Robot | attr_accessor :family 238*16467b97STreehugger Robot | attr_reader :name 239*16467b97STreehugger Robot | 240*16467b97STreehugger Robot | def eat( number ) 241*16467b97STreehugger Robot | puts( "ate %s %s" % [ number, @name ] ) 242*16467b97STreehugger Robot | end 243*16467b97STreehugger Robot | 244*16467b97STreehugger Robot | def to_s 245*16467b97STreehugger Robot | @name.to_s.dup 246*16467b97STreehugger Robot | end 247*16467b97STreehugger Robot | end 248*16467b97STreehugger Robot END 249*16467b97STreehugger Robot end 250*16467b97STreehugger Robotend 251