inversion 1.0.0 → 1.3.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 (60) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/History.rdoc +46 -0
  5. data/Manifest.txt +0 -1
  6. data/README.rdoc +10 -4
  7. data/Rakefile +4 -90
  8. data/bin/inversion +3 -1
  9. data/lib/inversion.rb +4 -4
  10. data/lib/inversion/command.rb +2 -1
  11. data/lib/inversion/exceptions.rb +4 -1
  12. data/lib/inversion/mixins.rb +30 -4
  13. data/lib/inversion/monkeypatches.rb +3 -2
  14. data/lib/inversion/parser.rb +2 -2
  15. data/lib/inversion/renderstate.rb +2 -1
  16. data/lib/inversion/sinatra.rb +4 -1
  17. data/lib/inversion/template.rb +3 -3
  18. data/lib/inversion/template/attrtag.rb +8 -6
  19. data/lib/inversion/template/begintag.rb +3 -1
  20. data/lib/inversion/template/calltag.rb +3 -1
  21. data/lib/inversion/template/codetag.rb +13 -2
  22. data/lib/inversion/template/commenttag.rb +3 -1
  23. data/lib/inversion/template/configtag.rb +10 -2
  24. data/lib/inversion/template/containertag.rb +2 -2
  25. data/lib/inversion/template/defaulttag.rb +4 -2
  26. data/lib/inversion/template/elsetag.rb +3 -1
  27. data/lib/inversion/template/elsiftag.rb +36 -7
  28. data/lib/inversion/template/endtag.rb +3 -3
  29. data/lib/inversion/template/escapetag.rb +3 -1
  30. data/lib/inversion/template/fortag.rb +14 -8
  31. data/lib/inversion/template/fragmenttag.rb +3 -1
  32. data/lib/inversion/template/iftag.rb +37 -8
  33. data/lib/inversion/template/importtag.rb +4 -2
  34. data/lib/inversion/template/includetag.rb +3 -1
  35. data/lib/inversion/template/node.rb +2 -1
  36. data/lib/inversion/template/pptag.rb +4 -2
  37. data/lib/inversion/template/publishtag.rb +3 -1
  38. data/lib/inversion/template/rescuetag.rb +3 -1
  39. data/lib/inversion/template/subscribetag.rb +3 -1
  40. data/lib/inversion/template/tag.rb +4 -4
  41. data/lib/inversion/template/textnode.rb +3 -1
  42. data/lib/inversion/template/timedeltatag.rb +16 -3
  43. data/lib/inversion/template/unlesstag.rb +31 -3
  44. data/lib/inversion/template/uriencodetag.rb +5 -5
  45. data/lib/inversion/template/yieldtag.rb +3 -1
  46. data/lib/inversion/tilt.rb +3 -1
  47. data/spec/helpers.rb +3 -0
  48. data/spec/inversion/mixins_spec.rb +14 -14
  49. data/spec/inversion/renderstate_spec.rb +0 -9
  50. data/spec/inversion/template/codetag_spec.rb +41 -1
  51. data/spec/inversion/template/elsiftag_spec.rb +25 -0
  52. data/spec/inversion/template/fortag_spec.rb +34 -2
  53. data/spec/inversion/template/iftag_spec.rb +11 -0
  54. data/spec/inversion/template/pptag_spec.rb +2 -0
  55. data/spec/inversion/template/timedeltatag_spec.rb +7 -0
  56. data/spec/inversion/template/unlesstag_spec.rb +11 -0
  57. data/spec/inversion/template_spec.rb +2 -6
  58. metadata +84 -121
  59. metadata.gz.sig +0 -0
  60. data/ChangeLog +0 -2078
@@ -1,6 +1,8 @@
1
- #!/usr/bin/env ruby
1
+ # -*- ruby -*-
2
+ # frozen_string_literal: true
2
3
  # vim: set noet nosta sw=4 ts=4 :
3
4
 
5
+ require 'inversion/template' unless defined?( Inversion::Template )
4
6
  require 'inversion/template/node'
5
7
 
6
8
  # Inversion text node class -- container for static content in templates between tags.
@@ -1,11 +1,15 @@
1
- #!/usr/bin/env ruby
1
+ # -*- ruby -*-
2
+ # frozen_string_literal: true
2
3
  # vim: set noet nosta sw=4 ts=4 :
3
4
 
4
5
  require 'uri'
5
6
  require 'time'
6
7
  require 'date'
8
+
9
+ require 'inversion/template' unless defined?( Inversion::Template )
7
10
  require 'inversion/template/attrtag'
8
11
 
12
+
9
13
  # Inversion time delta tag.
10
14
  #
11
15
  # This tag is a derivative of the 'attr' tag that transforms the results of its method call
@@ -37,6 +41,11 @@ class Inversion::Template::TimeDeltaTag < Inversion::Template::AttrTag
37
41
  def render( renderstate )
38
42
  val = super( renderstate )
39
43
  time = nil
44
+ omit_decorator = false
45
+
46
+ if val.respond_to?( :key )
47
+ val, omit_decorator = val.values_at( :time, :omit_decorator )
48
+ end
40
49
 
41
50
  if val.respond_to?( :to_time )
42
51
  time = val.to_time
@@ -49,10 +58,14 @@ class Inversion::Template::TimeDeltaTag < Inversion::Template::AttrTag
49
58
  now = Time.now
50
59
  if now > time
51
60
  seconds = now - time
52
- return "%s ago" % [ timeperiod(seconds) ]
61
+ period = timeperiod( seconds )
62
+ period += ' ago' unless omit_decorator
63
+ return period
53
64
  else
54
65
  seconds = time - now
55
- return "%s from now" % [ timeperiod(seconds) ]
66
+ period = timeperiod( seconds )
67
+ period += ' from now' unless omit_decorator
68
+ return period
56
69
  end
57
70
  end
58
71
 
@@ -1,7 +1,9 @@
1
- #!/usr/bin/env ruby
1
+ # -*- ruby -*-
2
+ # frozen_string_literal: true
2
3
  # vim: set noet nosta sw=4 ts=4 :
3
4
 
4
5
  require 'inversion/mixins'
6
+ require 'inversion/template' unless defined?( Inversion::Template )
5
7
  require 'inversion/template/attrtag'
6
8
  require 'inversion/template/containertag'
7
9
  require 'inversion/template/elsetag'
@@ -20,14 +22,40 @@ require 'inversion/template/elsetag'
20
22
  class Inversion::Template::UnlessTag < Inversion::Template::AttrTag
21
23
  include Inversion::Template::ContainerTag
22
24
 
23
- # Inherits AttrTag's tag patterns
25
+ # Inherit AttrTag's tag patterns first.
26
+ inherit_tag_patterns
27
+
28
+ # Append a 'not' tag matcher.
29
+ # <?unless ! foo ?>, <?unless !foo ?>
30
+ tag_pattern '$(op) sp* $(ident)' do |tag, match|
31
+ op = match.string( 1 )
32
+ raise Inversion::ParseError, "expected '!', got %p instead" % [ op ] unless op == '!'
33
+
34
+ tag.send( :log ).debug " Identifier is: %p (inverted)" % [ match.string(2) ]
35
+ tag.name = match.string( 2 ).to_sym
36
+ tag.inverted = true
37
+ end
38
+
39
+
40
+ ### Create a new UnlessTag.
41
+ def initialize( body, linenum=nil, colnum=nil )
42
+ @inverted = false
43
+ super
44
+ end
45
+
46
+ # Invert the tag's renderstate if created with the 'not' operator.
47
+ attr_accessor :inverted
48
+
24
49
 
25
50
  ### Render the tag's contents if the condition is true, or any else or elsif sections
26
51
  ### if the condition isn't true.
27
52
  def render( state )
28
53
 
54
+ evaluated_state = self.evaluate( state )
55
+ evaluated_state = ! evaluated_state if self.inverted
56
+
29
57
  # Start out with rendering *disabled* if the tag body evaluates trueishly
30
- if self.evaluate( state )
58
+ if evaluated_state
31
59
  self.log.debug "Initial state was TRUE; disabling rendering"
32
60
  state.disable_rendering
33
61
  else
@@ -1,7 +1,9 @@
1
- #!/usr/bin/env ruby
1
+ # -*- ruby -*-
2
+ # frozen_string_literal: true
2
3
  # vim: set noet nosta sw=4 ts=4 :
3
4
 
4
5
  require 'uri'
6
+ require 'inversion/template' unless defined?( Inversion::Template )
5
7
  require 'inversion/template/attrtag'
6
8
 
7
9
  # Inversion URL encoding tag.
@@ -14,16 +16,14 @@ require 'inversion/template/attrtag'
14
16
  # <?uriencode foo.bar ?>
15
17
  #
16
18
  class Inversion::Template::UriencodeTag < Inversion::Template::AttrTag
19
+ include Inversion::Escaping
17
20
 
18
- # Unreserved characters from section 2.3 of RFC 3986
19
- # ALPHA / DIGIT / "-" / "." / "_" / "~"
20
- DEFAULT_ENCODED_CHARACTERS = /[^\w\-\.~]/
21
21
 
22
22
  ### Render the method chains against the attributes of the specified +render_state+
23
23
  ### and return them.
24
24
  def render( render_state )
25
25
  raw = super
26
- return URI.encode( raw.to_s, DEFAULT_ENCODED_CHARACTERS )
26
+ return escape_uri( raw.to_s )
27
27
  end
28
28
 
29
29
  end # class Inversion::Template::UriencodeTag
@@ -1,8 +1,10 @@
1
- #!/usr/bin/env ruby
1
+ # -*- ruby -*-
2
+ # frozen_string_literal: true
2
3
  # vim: set noet nosta sw=4 ts=4 :
3
4
 
4
5
  require 'pathname'
5
6
  require 'inversion/mixins'
7
+ require 'inversion/template' unless defined?( Inversion::Template )
6
8
  require 'inversion/template/tag'
7
9
 
8
10
 
@@ -1,4 +1,6 @@
1
- #!/usr/bin/env ruby
1
+ # -*- ruby -*-
2
+ # frozen_string_literal: true
3
+ # vim: set noet nosta sw=4 ts=4 :
2
4
 
3
5
  require 'tilt'
4
6
 
@@ -5,6 +5,7 @@
5
5
  require 'simplecov' if ENV['COVERAGE']
6
6
 
7
7
  require 'rspec'
8
+ require 'rspec/wait'
8
9
  require 'loggability'
9
10
  require 'loggability/spechelpers'
10
11
 
@@ -44,6 +45,8 @@ RSpec.configure do |c|
44
45
  c.mock_with( :rspec ) do |mock|
45
46
  mock.syntax = :expect
46
47
  end
48
+ c.wait_timeout = 3
49
+ c.example_status_persistence_file_path = 'spec/.state'
47
50
 
48
51
  c.include( Inversion::SpecHelpers )
49
52
  c.include( Loggability::SpecHelpers )
@@ -108,7 +108,7 @@ describe Inversion, "mixins" do
108
108
  include Inversion::Escaping
109
109
 
110
110
  def render( state )
111
- return self.escape( "<something>", state )
111
+ return self.escape( "</something>", state )
112
112
  end
113
113
  end
114
114
  @obj = objclass.new
@@ -116,18 +116,28 @@ describe Inversion, "mixins" do
116
116
 
117
117
  it "adds configurable escaping to including classes" do
118
118
  render_state = Inversion::RenderState.new( {}, :escape_format => :html )
119
- expect( @obj.render( render_state ) ).to eq( "&lt;something&gt;" )
119
+ expect( @obj.render( render_state ) ).to eq( "&lt;/something&gt;" )
120
120
  end
121
121
 
122
122
  it "doesn't escape anything if escaping is disabled" do
123
123
  render_state = Inversion::RenderState.new( {}, :escape_format => nil )
124
- expect( @obj.render( render_state ) ).to eq( "<something>" )
124
+ expect( @obj.render( render_state ) ).to eq( "</something>" )
125
125
  end
126
126
 
127
127
  it "doesn't escape anything if escaping is set to ':none'" do
128
128
  render_state = Inversion::RenderState.new( {}, :escape_format => :none )
129
- expect( @obj.render( render_state ) ).to eq( "<something>" )
129
+ expect( @obj.render( render_state ) ).to eq( "</something>" )
130
130
  end
131
+
132
+ it "supports URI escaping" do
133
+ render_state = Inversion::RenderState.new( {}, :escape_format => :uri )
134
+
135
+ rval = @obj.render( render_state )
136
+
137
+ expect( rval.encoding ).to eq( Encoding::US_ASCII )
138
+ expect( rval ).to eq( "%3C%2Fsomething%3E" )
139
+ end
140
+
131
141
  end
132
142
 
133
143
 
@@ -235,16 +245,6 @@ describe Inversion, "mixins" do
235
245
  expect( copy.default_proc ).to eq( original.default_proc )
236
246
  end
237
247
 
238
- it "preserves taintedness of copied objects" do
239
- original = Object.new
240
- original.taint
241
-
242
- copy = Inversion::DataUtilities.deep_copy( original )
243
-
244
- expect( copy ).to_not be( original )
245
- expect( copy ).to be_tainted()
246
- end
247
-
248
248
  it "preserves frozen-ness of copied objects" do
249
249
  original = Object.new
250
250
  original.freeze
@@ -41,15 +41,6 @@ describe Inversion::RenderState do
41
41
  expect( state.scope[:bear] ).to_not equal( attributes[:bear] )
42
42
  end
43
43
 
44
- it "preserves tainted status when copying its attributes" do
45
- attributes = { :danger => "in pants" }
46
- attributes[:danger].taint
47
-
48
- state = Inversion::RenderState.new( attributes )
49
-
50
- expect( state.scope[:danger] ).to be_tainted()
51
- end
52
-
53
44
  it "preserves singleton methods on attribute objects when copying" do
54
45
  obj = Object.new
55
46
  def obj.foo; "foo!"; end
@@ -28,6 +28,46 @@ describe Inversion::Template::CodeTag do
28
28
  expect( subclass.tag_patterns.first[1].call(:dummy, :king_dummy) ).to eq( :foo )
29
29
  end
30
30
 
31
- end
32
31
 
32
+ it "can explicitly declare pattern inheritence" do
33
+ parentclass = Class.new( Inversion::Template::CodeTag ) do
34
+ tag_pattern "$(ident)" do |tag, match|
35
+ :foo
36
+ end
37
+ end
38
+
39
+ subclass = Class.new( parentclass ) do
40
+ inherit_tag_patterns
41
+ tag_pattern "$(op) $(ident)" do |tag, match|
42
+ :bar
43
+ end
44
+ end
45
+
46
+ expect( subclass.tag_patterns.size ).to eq( 2 )
47
+ expect( subclass.tag_patterns.first[0] ).
48
+ to be_an_instance_of( Inversion::Template::CodeTag::TokenPattern )
49
+ expect( subclass.tag_patterns.last[0] ).
50
+ to be_an_instance_of( Inversion::Template::CodeTag::TokenPattern )
51
+ expect( subclass.tag_patterns.first[1].call(:dummy, :king_dummy) ).to eq( :foo )
52
+ expect( subclass.tag_patterns.last[1].call(:dummy, :king_dummy) ).to eq( :bar )
53
+ end
54
+
55
+
56
+ it "throws an error if trying to inherit patterns after they are declared" do
57
+ parentclass = Class.new( Inversion::Template::CodeTag ) do
58
+ tag_pattern "$(ident)" do |tag, match|
59
+ :foo
60
+ end
61
+ end
62
+
63
+ expect {
64
+ Class.new( parentclass ) do
65
+ tag_pattern "$(op) $(ident)" do |tag, match|
66
+ :bar
67
+ end
68
+ inherit_tag_patterns
69
+ end
70
+ }.to raise_exception( ScriptError, /patterns already exist/i )
71
+ end
72
+ end
33
73
  end
@@ -58,6 +58,31 @@ describe Inversion::Template::ElsifTag do
58
58
  end
59
59
 
60
60
 
61
+ it "inverts its attribute with a ! operator" do
62
+ template = Inversion::Template.new( <<-END_TEMPLATE )
63
+ <?if thing ?>
64
+ Thing!
65
+ <?elsif ! otherthing ?>
66
+ Otherthing!
67
+ <?else ?>
68
+ Nope.
69
+ <?end?>
70
+ END_TEMPLATE
71
+
72
+ template.thing = true
73
+ template.otherthing = true
74
+ expect( template.render ).to include( "Thing!" )
75
+
76
+ template.thing = false
77
+ template.otherthing = false
78
+ expect( template.render ).to include( "Otherthing!" )
79
+
80
+ template.thing = false
81
+ template.otherthing = true
82
+ expect( template.render ).to include( "Nope." )
83
+ end
84
+
85
+
61
86
  it "renders as its attribute value if it's a simple attribute" do
62
87
  renderstate = Inversion::RenderState.new( :bar => :the_attribute_value )
63
88
  tag = Inversion::Template::ElsifTag.new( 'bar' )
@@ -11,12 +11,12 @@ require 'inversion/renderstate'
11
11
 
12
12
  describe Inversion::Template::ForTag do
13
13
 
14
-
15
14
  it "knows which identifiers should be added to the template" do
16
15
  tag = Inversion::Template::ForTag.new( 'foo in bar' )
17
16
  expect( tag.identifiers ).to eq( [ :bar ] )
18
17
  end
19
18
 
19
+
20
20
  it "can iterate over single items of a collection attribute" do
21
21
  tag = Inversion::Template::ForTag.new( 'foo in bar' )
22
22
 
@@ -24,6 +24,7 @@ describe Inversion::Template::ForTag do
24
24
  expect( tag.enumerator ).to eq( 'bar' )
25
25
  end
26
26
 
27
+
27
28
  it "should render as nothing if the corresponding attribute in the template is unset" do
28
29
  render_state = Inversion::RenderState.new( :bar => nil )
29
30
 
@@ -38,6 +39,7 @@ describe Inversion::Template::ForTag do
38
39
  expect( tag.render( render_state ) ).to be_nil()
39
40
  end
40
41
 
42
+
41
43
  it "renders each of its subnodes for each iteration, replacing its " +
42
44
  "block arguments with the yielded values" do
43
45
  render_state = Inversion::RenderState.new( :bar => %w[monkey goat] )
@@ -54,6 +56,7 @@ describe Inversion::Template::ForTag do
54
56
  expect( render_state.to_s ).to eq( "[monkey][goat]" )
55
57
  end
56
58
 
59
+
57
60
  it "supports nested iterators" do
58
61
  render_state = Inversion::RenderState.new( :tic => [ 'x', 'o'], :tac => ['o', 'x'] )
59
62
 
@@ -74,6 +77,7 @@ describe Inversion::Template::ForTag do
74
77
  expect( render_state.to_s ).to eq( "[x, o][x, x][o, o][o, x]" )
75
78
  end
76
79
 
80
+
77
81
  it "supports iterating over a range" do
78
82
 
79
83
  # <?for omarker in tic ?><?for imarker in tac ?>
@@ -87,12 +91,14 @@ describe Inversion::Template::ForTag do
87
91
  expect( render_state.to_s ).to eq( "0 1 2 3 4 5 6 7 8 9 10 " )
88
92
  end
89
93
 
94
+
90
95
  it "raises a ParseError if a keyword other than 'in' is used" do
91
96
  expect {
92
97
  Inversion::Template::ForTag.new( 'foo begin bar' )
93
98
  }.to raise_error( Inversion::ParseError, /invalid/i )
94
99
  end
95
100
 
101
+
96
102
  context "multidimensional collections" do
97
103
 
98
104
  it "can be expanded into multiple block arguments" do
@@ -103,6 +109,27 @@ describe Inversion::Template::ForTag do
103
109
  end
104
110
 
105
111
 
112
+ it "can be expanded by nesting" do
113
+ tmpl = Inversion::Template.new( <<-"END_TEMPLATE" )
114
+ <?for outer in numbers ?>
115
+ -
116
+ <?for inner in outer ?>
117
+ :<?attr inner ?>:
118
+ <?end for ?>
119
+ -
120
+ <?end for ?>
121
+ END_TEMPLATE
122
+
123
+ tmpl.numbers = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10]]
124
+ results = ''
125
+ wait_for { results = tmpl.render }.to be_a( String )
126
+
127
+ expect( results ).to match( /-\s+:1:\s+:2:\s+:3:\s*:4:\s+-/ )
128
+ expect( results ).to match( /-\s+:5:\s+:6:\s+:7:\s*:8:\s+-/ )
129
+ expect( results ).to match( /-\s+:9:\s+:10:\s+-/ )
130
+ end
131
+
132
+
106
133
  it "can be expanded into multiple block arguments (sans spaces)" do
107
134
  tag = Inversion::Template::ForTag.new( 'splip,splorp,sploop in splap' )
108
135
 
@@ -110,6 +137,7 @@ describe Inversion::Template::ForTag do
110
137
  expect( tag.enumerator ).to eq( 'splap' )
111
138
  end
112
139
 
140
+
113
141
  it "can be expanded into multiple block arguments from hash pairs" do
114
142
  tag = Inversion::Template::ForTag.new( 'key, value in splap' )
115
143
 
@@ -129,6 +157,7 @@ describe Inversion::Template::ForTag do
129
157
  expect( render_state.to_s ).to eq( '[one translates to uno][two translates to dos]' )
130
158
  end
131
159
 
160
+
132
161
  it "can be expanded into multiple block arguments with complex values" do
133
162
  # [<?attr key?> translates to <?attr value?>]
134
163
  tree = Inversion::Parser.new( nil ).parse( <<-"END_TEMPLATE" )
@@ -153,6 +182,7 @@ describe Inversion::Template::ForTag do
153
182
  expect( render_state.to_s ).to match( /ch \(1\) => ch/ )
154
183
  end
155
184
 
185
+
156
186
  it "preserves an array of subhashes" do
157
187
  tree = Inversion::Parser.new( nil ).parse( <<-"END_TEMPLATE" )
158
188
  <?for subhash in the_hash[:a] ?>
@@ -168,7 +198,7 @@ describe Inversion::Template::ForTag do
168
198
  render_state = Inversion::RenderState.new( :the_hash => the_hash )
169
199
  tree.first.render( render_state )
170
200
 
171
- expect( render_state.to_s ).to match( /Subhash is a Hash/i )
201
+ expect( render_state.to_s ).to match( /subhash is a hash.*subhash is a hash/i )
172
202
  end
173
203
 
174
204
  end
@@ -245,7 +275,9 @@ describe Inversion::Template::ForTag do
245
275
  </section>
246
276
  END_OUTPUT
247
277
  end
278
+
248
279
  end
280
+
249
281
  end
250
282
 
251
283