inversion 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. data.tar.gz.sig +2 -0
  2. data/.gemtest +0 -0
  3. data/ChangeLog +836 -0
  4. data/History.md +4 -0
  5. data/Manifest.txt +74 -0
  6. data/README.rdoc +171 -0
  7. data/Rakefile +55 -0
  8. data/bin/inversion +276 -0
  9. data/lib/inversion.rb +98 -0
  10. data/lib/inversion/exceptions.rb +21 -0
  11. data/lib/inversion/mixins.rb +236 -0
  12. data/lib/inversion/monkeypatches.rb +20 -0
  13. data/lib/inversion/renderstate.rb +337 -0
  14. data/lib/inversion/sinatra.rb +35 -0
  15. data/lib/inversion/template.rb +250 -0
  16. data/lib/inversion/template/attrtag.rb +120 -0
  17. data/lib/inversion/template/calltag.rb +16 -0
  18. data/lib/inversion/template/codetag.rb +164 -0
  19. data/lib/inversion/template/commenttag.rb +54 -0
  20. data/lib/inversion/template/conditionaltag.rb +49 -0
  21. data/lib/inversion/template/configtag.rb +60 -0
  22. data/lib/inversion/template/containertag.rb +45 -0
  23. data/lib/inversion/template/elsetag.rb +62 -0
  24. data/lib/inversion/template/elsiftag.rb +49 -0
  25. data/lib/inversion/template/endtag.rb +55 -0
  26. data/lib/inversion/template/escapetag.rb +26 -0
  27. data/lib/inversion/template/fortag.rb +120 -0
  28. data/lib/inversion/template/iftag.rb +69 -0
  29. data/lib/inversion/template/importtag.rb +70 -0
  30. data/lib/inversion/template/includetag.rb +51 -0
  31. data/lib/inversion/template/node.rb +102 -0
  32. data/lib/inversion/template/parser.rb +297 -0
  33. data/lib/inversion/template/pptag.rb +28 -0
  34. data/lib/inversion/template/publishtag.rb +72 -0
  35. data/lib/inversion/template/subscribetag.rb +88 -0
  36. data/lib/inversion/template/tag.rb +150 -0
  37. data/lib/inversion/template/textnode.rb +43 -0
  38. data/lib/inversion/template/unlesstag.rb +60 -0
  39. data/lib/inversion/template/uriencodetag.rb +30 -0
  40. data/lib/inversion/template/yieldtag.rb +51 -0
  41. data/lib/inversion/tilt.rb +82 -0
  42. data/lib/inversion/utils.rb +235 -0
  43. data/spec/data/sinatra/hello.inversion +1 -0
  44. data/spec/inversion/mixins_spec.rb +177 -0
  45. data/spec/inversion/monkeypatches_spec.rb +35 -0
  46. data/spec/inversion/renderstate_spec.rb +291 -0
  47. data/spec/inversion/sinatra_spec.rb +59 -0
  48. data/spec/inversion/template/attrtag_spec.rb +216 -0
  49. data/spec/inversion/template/calltag_spec.rb +30 -0
  50. data/spec/inversion/template/codetag_spec.rb +51 -0
  51. data/spec/inversion/template/commenttag_spec.rb +84 -0
  52. data/spec/inversion/template/configtag_spec.rb +105 -0
  53. data/spec/inversion/template/containertag_spec.rb +54 -0
  54. data/spec/inversion/template/elsetag_spec.rb +105 -0
  55. data/spec/inversion/template/elsiftag_spec.rb +87 -0
  56. data/spec/inversion/template/endtag_spec.rb +78 -0
  57. data/spec/inversion/template/escapetag_spec.rb +59 -0
  58. data/spec/inversion/template/fortag_spec.rb +98 -0
  59. data/spec/inversion/template/iftag_spec.rb +241 -0
  60. data/spec/inversion/template/importtag_spec.rb +106 -0
  61. data/spec/inversion/template/includetag_spec.rb +108 -0
  62. data/spec/inversion/template/node_spec.rb +81 -0
  63. data/spec/inversion/template/parser_spec.rb +170 -0
  64. data/spec/inversion/template/pptag_spec.rb +51 -0
  65. data/spec/inversion/template/publishtag_spec.rb +69 -0
  66. data/spec/inversion/template/subscribetag_spec.rb +60 -0
  67. data/spec/inversion/template/tag_spec.rb +97 -0
  68. data/spec/inversion/template/textnode_spec.rb +86 -0
  69. data/spec/inversion/template/unlesstag_spec.rb +84 -0
  70. data/spec/inversion/template/uriencodetag_spec.rb +49 -0
  71. data/spec/inversion/template/yieldtag_spec.rb +54 -0
  72. data/spec/inversion/template_spec.rb +269 -0
  73. data/spec/inversion/tilt_spec.rb +47 -0
  74. data/spec/inversion_spec.rb +95 -0
  75. data/spec/lib/constants.rb +9 -0
  76. data/spec/lib/helpers.rb +160 -0
  77. metadata +316 -0
  78. metadata.gz.sig +0 -0
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env rspec -cfd -b
2
+ # vim: set noet nosta sw=4 ts=4 :
3
+
4
+ BEGIN {
5
+ require 'pathname'
6
+ basedir = Pathname( __FILE__ ).dirname.parent.parent.parent
7
+ libdir = basedir + 'lib'
8
+
9
+ $LOAD_PATH.unshift( basedir.to_s ) unless $LOAD_PATH.include?( basedir.to_s )
10
+ $LOAD_PATH.unshift( libdir.to_s ) unless $LOAD_PATH.include?( libdir.to_s )
11
+ }
12
+
13
+ require 'rspec'
14
+ require 'spec/lib/helpers'
15
+ require 'inversion/template/pptag'
16
+
17
+ describe Inversion::Template::PpTag do
18
+
19
+ before( :all ) do
20
+ setup_logging( :fatal )
21
+ end
22
+
23
+ after( :all ) do
24
+ reset_logging()
25
+ end
26
+
27
+ before( :each ) do
28
+ @attribute_object = mock( "template attribute" )
29
+ end
30
+
31
+
32
+ it "dumps the results of rendering" do
33
+ template = Inversion::Template.
34
+ new( 'It looks like: <tt><?pp foo.bar ?></tt>.', :escape_format => :none )
35
+ template.foo = @attribute_object
36
+ @attribute_object.should_receive( :bar ).with( no_args() ).
37
+ and_return({ :a_complex => [:datastructure, :or, :something] })
38
+
39
+ template.render.should == "It looks like: <tt>{:a_complex=>[:datastructure, :or, :something]}</tt>."
40
+ end
41
+
42
+ it "escapes as HTML if the format is set to :html" do
43
+ template = Inversion::Template.
44
+ new( 'It looks like: <tt><?pp foo.bar ?></tt>.', :escape_format => :html )
45
+ template.foo = @attribute_object
46
+ @attribute_object.should_receive( :bar ).with( no_args() ).
47
+ and_return({ :a_complex => [:datastructure, :or, :something] })
48
+
49
+ template.render.should == "It looks like: <tt>{:a_complex=&gt;[:datastructure, :or, :something]}</tt>."
50
+ end
51
+ end
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env rspec -cfd -b
2
+ # vim: set noet nosta sw=4 ts=4 :
3
+
4
+ BEGIN {
5
+ require 'pathname'
6
+ basedir = Pathname( __FILE__ ).dirname.parent.parent.parent
7
+ libdir = basedir + 'lib'
8
+
9
+ $LOAD_PATH.unshift( basedir.to_s ) unless $LOAD_PATH.include?( basedir.to_s )
10
+ $LOAD_PATH.unshift( libdir.to_s ) unless $LOAD_PATH.include?( libdir.to_s )
11
+ }
12
+
13
+ require 'rspec'
14
+ require 'spec/lib/helpers'
15
+ require 'inversion/template/publishtag'
16
+
17
+ describe Inversion::Template::PublishTag do
18
+
19
+ class TestSubscriber
20
+ def initialize
21
+ @published_nodes = []
22
+ end
23
+
24
+ attr_reader :published_nodes
25
+
26
+ def publish( *nodes )
27
+ @published_nodes.push( *nodes )
28
+ end
29
+ end # class TestSubscriber
30
+
31
+
32
+ before( :all ) do
33
+ setup_logging( :fatal )
34
+ end
35
+
36
+ after( :all ) do
37
+ reset_logging()
38
+ end
39
+
40
+
41
+ it "raises a parse error if the body isn't a simple attribute" do
42
+ expect {
43
+ Inversion::Template::PublishTag.new( 'a.non-identifier' )
44
+ }.should raise_exception( Inversion::ParseError, /malformed key/i )
45
+ end
46
+
47
+
48
+ it "doesn't render its contents in the template it's declared in" do
49
+ Inversion::Template.new( "<?publish foo ?>Some stuff<?end ?>" ).render.should == ''
50
+ end
51
+
52
+
53
+ it "publishes its rendered nodes to the render state when rendered" do
54
+ contenttag = Inversion::Template::TextNode.new( 'elveses' )
55
+ publishtag = Inversion::Template::PublishTag.new( 'eventname' )
56
+ publishtag << contenttag
57
+
58
+ subscriber = TestSubscriber.new
59
+ renderstate = Inversion::RenderState.new
60
+ renderstate.subscribe( :eventname, subscriber )
61
+
62
+ publishtag.render( renderstate )
63
+
64
+ subscriber.published_nodes.should == [ 'elveses' ]
65
+ end
66
+
67
+ end
68
+
69
+
@@ -0,0 +1,60 @@
1
+ #!/usr/bin/env rspec -cfd -b
2
+ # vim: set noet nosta sw=4 ts=4 :
3
+
4
+ BEGIN {
5
+ require 'pathname'
6
+ basedir = Pathname( __FILE__ ).dirname.parent.parent.parent
7
+ libdir = basedir + 'lib'
8
+
9
+ $LOAD_PATH.unshift( basedir.to_s ) unless $LOAD_PATH.include?( basedir.to_s )
10
+ $LOAD_PATH.unshift( libdir.to_s ) unless $LOAD_PATH.include?( libdir.to_s )
11
+ }
12
+
13
+ require 'rspec'
14
+ require 'spec/lib/helpers'
15
+ require 'inversion/template'
16
+ require 'inversion/template/textnode'
17
+ require 'inversion/template/subscribetag'
18
+
19
+ describe Inversion::Template::SubscribeTag do
20
+
21
+ before( :all ) do
22
+ setup_logging( :fatal )
23
+ end
24
+
25
+ after( :all ) do
26
+ reset_logging()
27
+ end
28
+
29
+
30
+ it "raises a parse error if the key isn't a simple attribute" do
31
+ expect {
32
+ Inversion::Template::SubscribeTag.new( 'a.non-identifier' )
33
+ }.should raise_exception( Inversion::ParseError, /malformed subscribe/i )
34
+ end
35
+
36
+ it "renders the nodes published by an immediate subtemplate with the same key" do
37
+ template = Inversion::Template.new( '--<?subscribe stylesheets ?>--<?attr subtemplate ?>' )
38
+ subtemplate = Inversion::Template.new( '<?publish stylesheets ?>a style<?end?>(subtemplate)' )
39
+
40
+ template.subtemplate = subtemplate
41
+
42
+ template.render.should == '--a style--(subtemplate)'
43
+ end
44
+
45
+ it "doesn't render anything if there are no publications with its key" do
46
+ template = Inversion::Template.new( '--<?subscribe nostylesheets ?>--<?attr subtemplate ?>' )
47
+ subtemplate = Inversion::Template.new( '<?publish stylesheets ?>a style<?end?>(subtemplate)' )
48
+
49
+ template.subtemplate = subtemplate
50
+
51
+ template.render.should == '----(subtemplate)'
52
+ end
53
+
54
+ it "renders a default value if one is supplied" do
55
+ template = Inversion::Template.new( "<?subscribe not_here || default value! ?>" )
56
+ template.render.should == "default value!"
57
+ end
58
+ end
59
+
60
+
@@ -0,0 +1,97 @@
1
+ #!/usr/bin/env rspec -cfd -b
2
+ # vim: set noet nosta sw=4 ts=4 :
3
+
4
+ BEGIN {
5
+ require 'pathname'
6
+ basedir = Pathname( __FILE__ ).dirname.parent.parent.parent
7
+ libdir = basedir + 'lib'
8
+
9
+ $LOAD_PATH.unshift( basedir.to_s ) unless $LOAD_PATH.include?( basedir.to_s )
10
+ $LOAD_PATH.unshift( libdir.to_s ) unless $LOAD_PATH.include?( libdir.to_s )
11
+ }
12
+
13
+ require 'rspec'
14
+ require 'spec/lib/helpers'
15
+ require 'inversion/template/tag'
16
+
17
+ describe Inversion::Template::Tag do
18
+
19
+ before( :all ) do
20
+ setup_logging( :fatal )
21
+ @real_derivatives = Inversion::Template::Tag.derivatives.dup
22
+ @real_types = Inversion::Template::Tag.types.dup
23
+ end
24
+
25
+ before( :each ) do
26
+ Inversion::Template::Tag.derivatives.clear
27
+ Inversion::Template::Tag.types.clear
28
+ end
29
+
30
+ after( :all ) do
31
+ Inversion::Template::Tag.instance_variable_set( :@derivatives, @real_derivatives )
32
+ Inversion::Template::Tag.instance_variable_set( :@types, @real_types )
33
+ reset_logging()
34
+ end
35
+
36
+
37
+ it "loads pluggable types via Rubygems" do
38
+ Gem.stub( :find_files ).
39
+ with( Inversion::Template::Tag::TAG_PLUGIN_PATTERN ).
40
+ and_return([ 'inversion/template/zebratag.rb' ])
41
+ Inversion::Template::Tag.should_receive( :require ).
42
+ with( 'inversion/template/zebratag.rb' ).
43
+ and_return {
44
+ Class.new( Inversion::Template::Tag ) {
45
+ def self::name; "ZebraTag"; end
46
+ }
47
+ }
48
+ result = Inversion::Template::Tag.load_all
49
+ result.should be_a( Hash )
50
+ result.should have( 1 ).member
51
+ result.should have_key( :zebra )
52
+ result[:zebra].should be_a( Class )
53
+ result[:zebra].should < Inversion::Template::Tag
54
+ end
55
+
56
+ it "doesn't include abstract tag types in its loading mechanism" do
57
+ Gem.stub( :find_files ).
58
+ with( Inversion::Template::Tag::TAG_PLUGIN_PATTERN ).
59
+ and_return([ 'inversion/template/zebratag.rb' ])
60
+ Inversion::Template::Tag.should_receive( :require ).
61
+ with( 'inversion/template/zebratag.rb' ).
62
+ and_return {
63
+ Class.new( Inversion::Template::Tag ) {
64
+ include Inversion::AbstractClass
65
+ def self::name; "ZebraTag"; end
66
+ }
67
+ }
68
+ result = Inversion::Template::Tag.load_all
69
+ result.should be_a( Hash )
70
+ result.should == {}
71
+ end
72
+
73
+
74
+ it "raises an exception if told to create a tag with an invalid name" do
75
+ expect {
76
+ Inversion::Template::Tag.create( '', "employee.severance_amount.nonzero? ?>" )
77
+ }.to raise_error( ArgumentError, /invalid tag name/i )
78
+ end
79
+
80
+ describe "concrete subclass" do
81
+
82
+ before( :each ) do
83
+ @tagclass = Class.new( Inversion::Template::Tag ) do
84
+ def self::name; "Inversion::Template::ConcreteTag"; end
85
+ end
86
+ @tag = @tagclass.new( "the body" )
87
+ end
88
+
89
+
90
+ it "can render itself as a comment for template debugging" do
91
+ @tag.as_comment_body.should == %{Concrete "the body" at line ??, column ??}
92
+ end
93
+
94
+ end
95
+
96
+ end
97
+
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env rspec -cfd -b
2
+ # vim: set noet nosta sw=4 ts=4 :
3
+
4
+ BEGIN {
5
+ require 'pathname'
6
+ basedir = Pathname( __FILE__ ).dirname.parent.parent.parent
7
+ libdir = basedir + 'lib'
8
+
9
+ $LOAD_PATH.unshift( basedir.to_s ) unless $LOAD_PATH.include?( basedir.to_s )
10
+ $LOAD_PATH.unshift( libdir.to_s ) unless $LOAD_PATH.include?( libdir.to_s )
11
+ }
12
+
13
+ require 'rspec'
14
+ require 'spec/lib/helpers'
15
+ require 'inversion/template/textnode'
16
+
17
+ describe Inversion::Template::TextNode do
18
+
19
+ before( :all ) do
20
+ setup_logging( :fatal )
21
+ end
22
+
23
+ before( :each ) do
24
+ @state = Inversion::RenderState.new
25
+ @node = Inversion::Template::TextNode.new( "unto thee" )
26
+ end
27
+
28
+ after( :all ) do
29
+ reset_logging()
30
+ end
31
+
32
+
33
+ it "renders itself unchanged" do
34
+ @node.render( @state ).should == "unto thee"
35
+ end
36
+
37
+ it "renders a brief description when rendered as a comment" do
38
+ @node.as_comment_body.should == %{Text (9 bytes): "unto thee"}
39
+ end
40
+
41
+
42
+ context "beginning with a newline and containing only whitespace" do
43
+ before( :each ) do
44
+ @text = "\n\tSome stuff\nAnd some other stuff.\n "
45
+ @node.instance_variable_set( :@body, @text )
46
+ end
47
+
48
+ it "strips the leading newline if :strip_tag_lines is set" do
49
+ @state.options[:strip_tag_lines] = true
50
+ @node.render( @state ).should == "\tSome stuff\nAnd some other stuff.\n "
51
+ end
52
+
53
+ it "renders as-is if :strip_tag_lines is not set" do
54
+ @state.options[:strip_tag_lines] = false
55
+ @node.render( @state ).should == @text
56
+ end
57
+
58
+ end
59
+
60
+
61
+ context "with more than 40 bytes of content" do
62
+
63
+ LONGER_CONTENT = <<-END_CONTENT
64
+ <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt
65
+ ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
66
+ laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in
67
+ voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
68
+ cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
69
+ END_CONTENT
70
+
71
+ before( :each ) do
72
+ @node.instance_variable_set( :@body, LONGER_CONTENT )
73
+ end
74
+
75
+ it "renders only the first 40 bytes when rendered as a comment" do
76
+ expected_content = LONGER_CONTENT[0,40].dump
77
+ expected_content[-1,0] = '...'
78
+
79
+ @node.as_comment_body.should ==
80
+ %Q{Text (488 bytes): "\\t\\t<p>Lorem ipsum dolor sit amet, consect..."}
81
+ end
82
+
83
+ end
84
+
85
+ end
86
+
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env rspec -cfd -b
2
+ # vim: set noet nosta sw=4 ts=4 :
3
+
4
+ BEGIN {
5
+ require 'pathname'
6
+ basedir = Pathname( __FILE__ ).dirname.parent.parent.parent
7
+ libdir = basedir + 'lib'
8
+
9
+ $LOAD_PATH.unshift( basedir.to_s ) unless $LOAD_PATH.include?( basedir.to_s )
10
+ $LOAD_PATH.unshift( libdir.to_s ) unless $LOAD_PATH.include?( libdir.to_s )
11
+ }
12
+
13
+ require 'rspec'
14
+ require 'spec/lib/helpers'
15
+ require 'inversion/template/unlesstag'
16
+ require 'inversion/template/textnode'
17
+ require 'inversion/renderstate'
18
+
19
+ describe Inversion::Template::UnlessTag do
20
+
21
+ before( :all ) do
22
+ setup_logging( :fatal )
23
+ end
24
+
25
+ after( :all ) do
26
+ reset_logging()
27
+ end
28
+
29
+
30
+ it "renders its contents if its attribute is false" do
31
+ tag = Inversion::Template::UnlessTag.new( 'attribute' )
32
+ tag << Inversion::Template::TextNode.new( 'the body' )
33
+
34
+ renderstate = Inversion::RenderState.new( :attribute => false )
35
+ tag.render( renderstate ).to_s.should == 'the body'
36
+ end
37
+
38
+ it "renders its contents if its methodchain is false" do
39
+ tag = Inversion::Template::UnlessTag.new( 'attribute.key?(:foo)' )
40
+ tag << Inversion::Template::TextNode.new( 'the body' )
41
+
42
+ renderstate = Inversion::RenderState.new( :attribute => {:bar => 1} )
43
+ tag.render( renderstate ).to_s.should == 'the body'
44
+ end
45
+
46
+ it "doesn't render its contents if its attribute is true" do
47
+ tag = Inversion::Template::UnlessTag.new( 'attribute' )
48
+ tag << Inversion::Template::TextNode.new( 'the body' )
49
+
50
+ renderstate = Inversion::RenderState.new( :attribute => true )
51
+ tag.render( renderstate ).to_s.should == ''
52
+ end
53
+
54
+ it "doesn't render its contents if its methodchain is true" do
55
+ tag = Inversion::Template::UnlessTag.new( 'attribute.key?(:foo)' )
56
+ tag << Inversion::Template::TextNode.new( 'the body' )
57
+
58
+ renderstate = Inversion::RenderState.new( :attribute => {:foo => 1} )
59
+ tag.render( renderstate ).to_s.should == ''
60
+ end
61
+
62
+ context "with an 'else' clause" do
63
+
64
+ before( :each ) do
65
+ @tag = Inversion::Template::UnlessTag.new( 'attribute' )
66
+ @tag << Inversion::Template::TextNode.new( 'the body before else' )
67
+ @tag << Inversion::Template::ElseTag.new
68
+ @tag << Inversion::Template::TextNode.new( 'the body after else' )
69
+
70
+ end
71
+
72
+ it "only renders the second half of the contents if its attribute is true" do
73
+ renderstate = Inversion::RenderState.new( :attribute => true )
74
+ @tag.render( renderstate ).to_s.should == 'the body after else'
75
+ end
76
+
77
+ it "only renders the first half of the contents if its attribute is false" do
78
+ renderstate = Inversion::RenderState.new( :attribute => false )
79
+ @tag.render( renderstate ).to_s.should == 'the body before else'
80
+ end
81
+
82
+ end
83
+
84
+ end