inversion 0.6.1 → 0.7.0

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.
data.tar.gz.sig CHANGED
Binary file
data/History.rdoc CHANGED
@@ -1,3 +1,9 @@
1
+ == v0.7.0 [2012-03-29] Michael Granger <ged@FaerieMUD.org>
2
+
3
+ - Switch to a much more flexible way to render tag bodies. This should
4
+ resolve most of the problems we've encountered with complex templates.
5
+
6
+
1
7
  == v0.6.1 [2012-03-16] Michael Granger <ged@FaerieMUD.org>
2
8
 
3
9
  - Commented out some of the more expensive debug logging for an order
data/Rakefile CHANGED
@@ -35,6 +35,7 @@ hoespec = Hoe.spec 'inversion' do
35
35
  self.dependency 'sysexits', '~> 1.0', :development
36
36
 
37
37
  self.spec_extras[:licenses] = ["BSD"]
38
+ self.spec_extras[:rdoc_options] = ['-f', 'fivefish', '-t', 'Inversion Templates']
38
39
  self.require_ruby_version( '>=1.9.2' )
39
40
  self.hg_sign_tags = true if self.respond_to?( :hg_sign_tags= )
40
41
  self.check_history_on_release = true if self.respond_to?( :check_history_on_release= )
data/lib/inversion.rb CHANGED
@@ -26,10 +26,10 @@ module Inversion
26
26
  require 'inversion/monkeypatches'
27
27
 
28
28
  # Library version constant
29
- VERSION = '0.6.1'
29
+ VERSION = '0.7.0'
30
30
 
31
31
  # Version-control revision constant
32
- REVISION = %q$Revision: 1947a577fae1 $
32
+ REVISION = %q$Revision: 92c2961cf986 $
33
33
 
34
34
  #
35
35
  # Logging
@@ -8,6 +8,63 @@ require 'inversion' unless defined?( Inversion )
8
8
  class Inversion::RenderState
9
9
  include Inversion::Loggable
10
10
 
11
+
12
+ # An encapsulation of the scope in which the bodies of tags evaluate. It's
13
+ # used to provide a controlled, isolated namespace which remains the same from
14
+ # tag to tag.
15
+ class Scope < BasicObject
16
+
17
+ ### Create a new RenderState::Scope with its initial tag locals set to
18
+ ### +locals+.
19
+ def initialize( locals={} )
20
+ @locals = locals
21
+ end
22
+
23
+
24
+ ### Return the tag local with the specified +name+.
25
+ def []( name )
26
+ return @locals[ name.to_sym ]
27
+ end
28
+
29
+
30
+ ### Set the tag local with the specified +name+ to +value+.
31
+ def []=( name, value )
32
+ @locals[ name.to_sym ] = value
33
+ end
34
+
35
+
36
+ ### Return a copy of the receiving Scope merged with the given +values+,
37
+ ### which can be either another Scope or a Hash.
38
+ def +( values )
39
+ # Have to do it this kludgy way because Scopes don't have #respond_to?
40
+ begin
41
+ return Scope.new( @locals.merge(values.__locals__) )
42
+ rescue ::NameError
43
+ return Scope.new( @locals.merge(values) )
44
+ end
45
+ end
46
+
47
+
48
+ ### Return the Hash of tag locals the belongs to this scope.
49
+ def __locals__
50
+ return @locals
51
+ end
52
+
53
+
54
+ #########
55
+ protected
56
+ #########
57
+
58
+ ### The main trickery behind this class -- intercept tag locals as method calls
59
+ ### and map them into values from the Scope's locals.
60
+ def method_missing( sym, *args, &block )
61
+ return super unless sym =~ /^\w+$/
62
+ @locals[ sym ]
63
+ end
64
+
65
+ end # class Scope
66
+
67
+
11
68
  ### Create a new RenderState. If the template is being rendered inside another one, the
12
69
  ### containing template's RenderState will be passed as the +containerstate+. The
13
70
  ### +initial_attributes+ will be deep-copied, and the +options+ will be merged with
@@ -25,10 +82,12 @@ class Inversion::RenderState
25
82
  # self.log.debug "Creating a render state with attributes: %p" %
26
83
  # [ initial_attributes ]
27
84
 
85
+ locals = deep_copy( initial_attributes )
86
+ @scopes = [ Scope.new(locals) ]
87
+
28
88
  @start_time = Time.now
29
89
  @containerstate = containerstate
30
90
  @options = Inversion::Template::DEFAULT_CONFIG.merge( options )
31
- @attributes = [ deep_copy(initial_attributes) ]
32
91
  @block = block
33
92
  @default_errhandler = self.method( :default_error_handler )
34
93
  @errhandler = @default_errhandler
@@ -77,8 +136,8 @@ class Inversion::RenderState
77
136
 
78
137
  ### Return the hash of attributes that are currently in effect in the
79
138
  ### rendering state.
80
- def attributes
81
- return @attributes.last
139
+ def scope
140
+ return @scopes.last
82
141
  end
83
142
 
84
143
 
@@ -92,7 +151,13 @@ class Inversion::RenderState
92
151
  ### return the result.
93
152
  def eval( code )
94
153
  self.log.debug "Evaling: %p" [ code ]
95
- return self.instance_eval( code )
154
+ return self.scope.instance_eval( code )
155
+ end
156
+
157
+
158
+ ### Backward-compatibility -- return the tag locals of the current scope as a Hash.
159
+ def attributes
160
+ return self.scope.__locals__
96
161
  end
97
162
 
98
163
 
@@ -103,10 +168,11 @@ class Inversion::RenderState
103
168
  self.log.debug "Overriding template attributes with: %p" % [ overrides ]
104
169
 
105
170
  begin
106
- @attributes.push( @attributes.last.merge(overrides) )
171
+ newscope = self.scope + overrides
172
+ @scopes.push( newscope )
107
173
  yield( self )
108
174
  ensure
109
- @attributes.pop
175
+ @scopes.pop
110
176
  end
111
177
  end
112
178
 
@@ -178,7 +244,8 @@ class Inversion::RenderState
178
244
  ### Merge the attributes and options of the +otherstate+ with those of the receiver,
179
245
  ### replacing any with the same keys.
180
246
  def merge!( otherstate )
181
- self.attributes.merge!( otherstate.attributes )
247
+ @scopes.push( @scopes.pop + otherstate.scope )
248
+ # self.attributes.merge!( otherstate.attributes )
182
249
  self.options.merge!( otherstate.options )
183
250
  return self
184
251
  end
@@ -331,11 +398,11 @@ class Inversion::RenderState
331
398
 
332
399
  ### Return a human-readable representation of the object.
333
400
  def inspect
334
- return "#<%p:0x%08x containerstate: %s, attributes: %s, destination: %p>" % [
401
+ return "#<%p:0x%08x containerstate: %s, scope locals: %s, destination: %p>" % [
335
402
  self.class,
336
403
  self.object_id / 2,
337
404
  self.containerstate ? "0x%08x" % [ self.containerstate.object_id ] : "nil",
338
- self.attributes.keys.sort.join(', '),
405
+ self.scope.__locals__.keys.sort.join(', '),
339
406
  self.destination.class,
340
407
  ]
341
408
  end
@@ -364,9 +431,9 @@ class Inversion::RenderState
364
431
 
365
432
  ### Handle attribute methods.
366
433
  def method_missing( sym, *args, &block )
367
- return super unless sym.to_s =~ /^[a-z]\w+[\?=!]?$/
368
- self.log.debug "mapping missing method call to attribute: %p" % [ sym ]
369
- return self.attributes[ sym ]
434
+ return super unless sym.to_s =~ /^\w+$/
435
+ self.log.debug "mapping missing method call to tag local: %p" % [ sym ]
436
+ return self.scope[ sym ]
370
437
  end
371
438
 
372
439
 
@@ -79,10 +79,7 @@ class Inversion::Template::AttrTag < Inversion::Template::CodeTag
79
79
 
80
80
  ### Render the tag attributes of the specified +renderstate+ and return them.
81
81
  def render( renderstate )
82
- # self.log.debug "Rendering %p with state: %p" % [ self, renderstate ]
83
-
84
- # Evaluate the tag body and return either false value
85
- value = self.evaluate( renderstate ) or return value
82
+ value = self.evaluate( renderstate ) # :FIXME: or return value # nil or false?
86
83
 
87
84
  # Apply the format if there is one
88
85
  if self.format
@@ -95,21 +92,8 @@ class Inversion::Template::AttrTag < Inversion::Template::CodeTag
95
92
 
96
93
  ### Evaluate the body of the tag in the context of +renderstate+ and return the results.
97
94
  def evaluate( renderstate )
98
- value = nil
99
- attribute = renderstate.attributes[ self.name.to_sym ]
100
- # self.log.debug " initial attribute: %p" % [ attribute ]
101
-
102
- # Evaluate the method chain (if there is one) against the attribute
103
- if self.methodchain
104
- methodchain = "self" + self.methodchain
105
- # self.log.debug " evaling methodchain: %p on: %p" % [ methodchain, attribute ]
106
- value = attribute.instance_eval( methodchain )
107
- else
108
- value = attribute
109
- end
110
- # self.log.debug " evaluated value: %p" % [ value ]
111
-
112
- return value
95
+ code = [ self.name.to_s, self.methodchain ].join( '' )
96
+ return renderstate.eval( code )
113
97
  end
114
98
 
115
99
 
@@ -48,11 +48,11 @@ describe Inversion::RenderState do
48
48
 
49
49
  state = Inversion::RenderState.new( attributes )
50
50
 
51
- state.attributes.should_not equal( attributes )
52
- state.attributes[:foot].should == "in mouth"
53
- state.attributes[:foot].should_not equal( attributes[:foot] )
54
- state.attributes[:bear].should == "in woods"
55
- state.attributes[:bear].should_not equal( attributes[:bear] )
51
+ state.scope.__locals__.should_not equal( attributes )
52
+ state.scope[:foot].should == "in mouth"
53
+ state.scope[:foot].should_not equal( attributes[:foot] )
54
+ state.scope[:bear].should == "in woods"
55
+ state.scope[:bear].should_not equal( attributes[:bear] )
56
56
  end
57
57
 
58
58
  it "preserves tainted status when copying its attributes" do
@@ -61,7 +61,7 @@ describe Inversion::RenderState do
61
61
 
62
62
  state = Inversion::RenderState.new( attributes )
63
63
 
64
- state.attributes[:danger].should be_tainted()
64
+ state.scope[:danger].should be_tainted()
65
65
  end
66
66
 
67
67
  it "preserves singleton methods on attribute objects when copying" do
@@ -70,7 +70,7 @@ describe Inversion::RenderState do
70
70
 
71
71
  state = Inversion::RenderState.new( :foo => obj )
72
72
 
73
- state.attributes[:foo].singleton_methods.map( &:to_sym ).should include( :foo )
73
+ state.scope[:foo].singleton_methods.map( &:to_sym ).should include( :foo )
74
74
  end
75
75
 
76
76
  it "preserves frozen status when copying its attributes" do
@@ -79,7 +79,7 @@ describe Inversion::RenderState do
79
79
 
80
80
  state = Inversion::RenderState.new( attributes )
81
81
 
82
- state.attributes[:danger].should be_frozen()
82
+ state.scope[:danger].should be_frozen()
83
83
  end
84
84
 
85
85
  it "can override its attributes for the duration of a block" do
@@ -92,7 +92,7 @@ describe Inversion::RenderState do
92
92
  state.bear.should == 'in woods'
93
93
  end
94
94
 
95
- state.attributes[:foot].should == 'in mouth'
95
+ state.scope[:foot].should == 'in mouth'
96
96
  end
97
97
 
98
98
 
@@ -107,7 +107,7 @@ describe Inversion::RenderState do
107
107
  end
108
108
  }.to raise_error()
109
109
 
110
- state.attributes[:foot].should == 'in mouth'
110
+ state.scope[:foot].should == 'in mouth'
111
111
  end
112
112
 
113
113
 
@@ -117,14 +117,18 @@ describe Inversion::RenderState do
117
117
  }.to raise_error( LocalJumpError, /no block/i )
118
118
  end
119
119
 
120
- it "provides accessor methods for its attributes" do
121
- state = Inversion::RenderState.new( :bar => :the_attribute_value )
122
- state.bar.should == :the_attribute_value
123
- end
120
+ describe Inversion::RenderState::Scope do
121
+
122
+ it "provides accessor methods for its attributes" do
123
+ state = Inversion::RenderState.new( :bar => :the_attribute_value )
124
+ state.scope.bar.should == :the_attribute_value
125
+ end
126
+
127
+ it "doesn't error if an accessor for a non-existant attribute is called" do
128
+ state = Inversion::RenderState.new( :bar => :the_attribute_value )
129
+ state.scope.foo.should be_nil()
130
+ end
124
131
 
125
- it "doesn't error if an accessor for a non-existant attribute is called" do
126
- state = Inversion::RenderState.new( :bar => :the_attribute_value )
127
- state.foo.should be_nil()
128
132
  end
129
133
 
130
134
  it "can be merged with another RenderState" do
@@ -132,8 +132,10 @@ describe Inversion::Template::AttrTag do
132
132
  end
133
133
 
134
134
  it "doesn't error if the attribute isn't set on the template" do
135
- state = Inversion::RenderState.new( :foo => nil )
136
- @tag.render( state ).should == nil
135
+ pending "recalling why we did this" do
136
+ state = Inversion::RenderState.new( :foo => nil )
137
+ @tag.render( state ).should == nil
138
+ end
137
139
  end
138
140
 
139
141
  it "can render itself as a comment for template debugging" do
@@ -199,6 +201,17 @@ describe Inversion::Template::AttrTag do
199
201
 
200
202
  template.render.should == "this is the result"
201
203
  end
204
+
205
+ it "renders method calls with template attribute arguments" do
206
+ template = Inversion::Template.new( 'this is <?attr foo.bar( baz ) ?>' )
207
+ foo = mock( "foo attribute object" )
208
+
209
+ template.foo = foo
210
+ template.baz = 18
211
+ foo.should_receive( :bar ).with( 18 ).and_return( "the result of calling bar" )
212
+
213
+ template.render.should == "this is the result of calling bar"
214
+ end
202
215
  end
203
216
 
204
217
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: inversion
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.7.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -37,33 +37,33 @@ cert_chain:
37
37
  YUhDS0xaZFNLai9SSHVUT3QrZ2JsUmV4OEZBaDhOZUEKY21saFhlNDZwWk5K
38
38
  Z1dLYnhaYWg4NWpJang5NWhSOHZPSStOQU01aUg5a09xSzEzRHJ4YWNUS1Bo
39
39
  cWo1UGp3RgotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
40
- date: 2012-03-16 00:00:00.000000000 Z
40
+ date: 2012-03-30 00:00:00.000000000 Z
41
41
  dependencies:
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: hoe-mercurial
44
- requirement: &70264152436760 !ruby/object:Gem::Requirement
44
+ requirement: &70356568944040 !ruby/object:Gem::Requirement
45
45
  none: false
46
46
  requirements:
47
47
  - - ~>
48
48
  - !ruby/object:Gem::Version
49
- version: 1.3.1
49
+ version: 1.4.0
50
50
  type: :development
51
51
  prerelease: false
52
- version_requirements: *70264152436760
52
+ version_requirements: *70356568944040
53
53
  - !ruby/object:Gem::Dependency
54
54
  name: hoe-manualgen
55
- requirement: &70264152436060 !ruby/object:Gem::Requirement
55
+ requirement: &70356568943280 !ruby/object:Gem::Requirement
56
56
  none: false
57
57
  requirements:
58
58
  - - ~>
59
59
  - !ruby/object:Gem::Version
60
- version: 0.2.0
60
+ version: 0.3.0
61
61
  type: :development
62
62
  prerelease: false
63
- version_requirements: *70264152436060
63
+ version_requirements: *70356568943280
64
64
  - !ruby/object:Gem::Dependency
65
65
  name: hoe-highline
66
- requirement: &70264152435540 !ruby/object:Gem::Requirement
66
+ requirement: &70356568942000 !ruby/object:Gem::Requirement
67
67
  none: false
68
68
  requirements:
69
69
  - - ~>
@@ -71,21 +71,21 @@ dependencies:
71
71
  version: 0.0.1
72
72
  type: :development
73
73
  prerelease: false
74
- version_requirements: *70264152435540
74
+ version_requirements: *70356568942000
75
75
  - !ruby/object:Gem::Dependency
76
76
  name: rdoc
77
- requirement: &70264152478140 !ruby/object:Gem::Requirement
77
+ requirement: &70356568957180 !ruby/object:Gem::Requirement
78
78
  none: false
79
79
  requirements:
80
80
  - - ~>
81
81
  - !ruby/object:Gem::Version
82
- version: '3.12'
82
+ version: '3.10'
83
83
  type: :development
84
84
  prerelease: false
85
- version_requirements: *70264152478140
85
+ version_requirements: *70356568957180
86
86
  - !ruby/object:Gem::Dependency
87
87
  name: rspec
88
- requirement: &70264152477360 !ruby/object:Gem::Requirement
88
+ requirement: &70356568956420 !ruby/object:Gem::Requirement
89
89
  none: false
90
90
  requirements:
91
91
  - - ~>
@@ -93,10 +93,10 @@ dependencies:
93
93
  version: '2.8'
94
94
  type: :development
95
95
  prerelease: false
96
- version_requirements: *70264152477360
96
+ version_requirements: *70356568956420
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: tilt
99
- requirement: &70264152476740 !ruby/object:Gem::Requirement
99
+ requirement: &70356568955640 !ruby/object:Gem::Requirement
100
100
  none: false
101
101
  requirements:
102
102
  - - ~>
@@ -104,10 +104,10 @@ dependencies:
104
104
  version: '1.3'
105
105
  type: :development
106
106
  prerelease: false
107
- version_requirements: *70264152476740
107
+ version_requirements: *70356568955640
108
108
  - !ruby/object:Gem::Dependency
109
109
  name: sinatra
110
- requirement: &70264152475940 !ruby/object:Gem::Requirement
110
+ requirement: &70356568954760 !ruby/object:Gem::Requirement
111
111
  none: false
112
112
  requirements:
113
113
  - - ~>
@@ -115,10 +115,10 @@ dependencies:
115
115
  version: '1.2'
116
116
  type: :development
117
117
  prerelease: false
118
- version_requirements: *70264152475940
118
+ version_requirements: *70356568954760
119
119
  - !ruby/object:Gem::Dependency
120
120
  name: rack-test
121
- requirement: &70264152474980 !ruby/object:Gem::Requirement
121
+ requirement: &70356568954020 !ruby/object:Gem::Requirement
122
122
  none: false
123
123
  requirements:
124
124
  - - ~>
@@ -126,10 +126,10 @@ dependencies:
126
126
  version: '0.6'
127
127
  type: :development
128
128
  prerelease: false
129
- version_requirements: *70264152474980
129
+ version_requirements: *70356568954020
130
130
  - !ruby/object:Gem::Dependency
131
131
  name: simplecov
132
- requirement: &70264152474040 !ruby/object:Gem::Requirement
132
+ requirement: &70356568953240 !ruby/object:Gem::Requirement
133
133
  none: false
134
134
  requirements:
135
135
  - - ~>
@@ -137,10 +137,10 @@ dependencies:
137
137
  version: '0.4'
138
138
  type: :development
139
139
  prerelease: false
140
- version_requirements: *70264152474040
140
+ version_requirements: *70356568953240
141
141
  - !ruby/object:Gem::Dependency
142
142
  name: trollop
143
- requirement: &70264152472820 !ruby/object:Gem::Requirement
143
+ requirement: &70356568952520 !ruby/object:Gem::Requirement
144
144
  none: false
145
145
  requirements:
146
146
  - - ~>
@@ -148,10 +148,10 @@ dependencies:
148
148
  version: '1.16'
149
149
  type: :development
150
150
  prerelease: false
151
- version_requirements: *70264152472820
151
+ version_requirements: *70356568952520
152
152
  - !ruby/object:Gem::Dependency
153
153
  name: highline
154
- requirement: &70264152471760 !ruby/object:Gem::Requirement
154
+ requirement: &70356568951720 !ruby/object:Gem::Requirement
155
155
  none: false
156
156
  requirements:
157
157
  - - ~>
@@ -159,10 +159,10 @@ dependencies:
159
159
  version: '1.6'
160
160
  type: :development
161
161
  prerelease: false
162
- version_requirements: *70264152471760
162
+ version_requirements: *70356568951720
163
163
  - !ruby/object:Gem::Dependency
164
164
  name: sysexits
165
- requirement: &70264152471180 !ruby/object:Gem::Requirement
165
+ requirement: &70356568950980 !ruby/object:Gem::Requirement
166
166
  none: false
167
167
  requirements:
168
168
  - - ~>
@@ -170,18 +170,18 @@ dependencies:
170
170
  version: '1.0'
171
171
  type: :development
172
172
  prerelease: false
173
- version_requirements: *70264152471180
173
+ version_requirements: *70356568950980
174
174
  - !ruby/object:Gem::Dependency
175
175
  name: hoe
176
- requirement: &70264152486800 !ruby/object:Gem::Requirement
176
+ requirement: &70356568950160 !ruby/object:Gem::Requirement
177
177
  none: false
178
178
  requirements:
179
179
  - - ~>
180
180
  - !ruby/object:Gem::Version
181
- version: '2.16'
181
+ version: '3.0'
182
182
  type: :development
183
183
  prerelease: false
184
- version_requirements: *70264152486800
184
+ version_requirements: *70356568950160
185
185
  description: ! 'Inversion is a templating system for Ruby. It uses the "Inversion
186
186
  of Control"
187
187
 
@@ -288,8 +288,10 @@ licenses:
288
288
  - BSD
289
289
  post_install_message:
290
290
  rdoc_options:
291
- - --main
292
- - README.rdoc
291
+ - -f
292
+ - fivefish
293
+ - -t
294
+ - Inversion Templates
293
295
  require_paths:
294
296
  - lib
295
297
  required_ruby_version: !ruby/object:Gem::Requirement
metadata.gz.sig CHANGED
Binary file