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.
- data.tar.gz.sig +2 -0
- data/.gemtest +0 -0
- data/ChangeLog +836 -0
- data/History.md +4 -0
- data/Manifest.txt +74 -0
- data/README.rdoc +171 -0
- data/Rakefile +55 -0
- data/bin/inversion +276 -0
- data/lib/inversion.rb +98 -0
- data/lib/inversion/exceptions.rb +21 -0
- data/lib/inversion/mixins.rb +236 -0
- data/lib/inversion/monkeypatches.rb +20 -0
- data/lib/inversion/renderstate.rb +337 -0
- data/lib/inversion/sinatra.rb +35 -0
- data/lib/inversion/template.rb +250 -0
- data/lib/inversion/template/attrtag.rb +120 -0
- data/lib/inversion/template/calltag.rb +16 -0
- data/lib/inversion/template/codetag.rb +164 -0
- data/lib/inversion/template/commenttag.rb +54 -0
- data/lib/inversion/template/conditionaltag.rb +49 -0
- data/lib/inversion/template/configtag.rb +60 -0
- data/lib/inversion/template/containertag.rb +45 -0
- data/lib/inversion/template/elsetag.rb +62 -0
- data/lib/inversion/template/elsiftag.rb +49 -0
- data/lib/inversion/template/endtag.rb +55 -0
- data/lib/inversion/template/escapetag.rb +26 -0
- data/lib/inversion/template/fortag.rb +120 -0
- data/lib/inversion/template/iftag.rb +69 -0
- data/lib/inversion/template/importtag.rb +70 -0
- data/lib/inversion/template/includetag.rb +51 -0
- data/lib/inversion/template/node.rb +102 -0
- data/lib/inversion/template/parser.rb +297 -0
- data/lib/inversion/template/pptag.rb +28 -0
- data/lib/inversion/template/publishtag.rb +72 -0
- data/lib/inversion/template/subscribetag.rb +88 -0
- data/lib/inversion/template/tag.rb +150 -0
- data/lib/inversion/template/textnode.rb +43 -0
- data/lib/inversion/template/unlesstag.rb +60 -0
- data/lib/inversion/template/uriencodetag.rb +30 -0
- data/lib/inversion/template/yieldtag.rb +51 -0
- data/lib/inversion/tilt.rb +82 -0
- data/lib/inversion/utils.rb +235 -0
- data/spec/data/sinatra/hello.inversion +1 -0
- data/spec/inversion/mixins_spec.rb +177 -0
- data/spec/inversion/monkeypatches_spec.rb +35 -0
- data/spec/inversion/renderstate_spec.rb +291 -0
- data/spec/inversion/sinatra_spec.rb +59 -0
- data/spec/inversion/template/attrtag_spec.rb +216 -0
- data/spec/inversion/template/calltag_spec.rb +30 -0
- data/spec/inversion/template/codetag_spec.rb +51 -0
- data/spec/inversion/template/commenttag_spec.rb +84 -0
- data/spec/inversion/template/configtag_spec.rb +105 -0
- data/spec/inversion/template/containertag_spec.rb +54 -0
- data/spec/inversion/template/elsetag_spec.rb +105 -0
- data/spec/inversion/template/elsiftag_spec.rb +87 -0
- data/spec/inversion/template/endtag_spec.rb +78 -0
- data/spec/inversion/template/escapetag_spec.rb +59 -0
- data/spec/inversion/template/fortag_spec.rb +98 -0
- data/spec/inversion/template/iftag_spec.rb +241 -0
- data/spec/inversion/template/importtag_spec.rb +106 -0
- data/spec/inversion/template/includetag_spec.rb +108 -0
- data/spec/inversion/template/node_spec.rb +81 -0
- data/spec/inversion/template/parser_spec.rb +170 -0
- data/spec/inversion/template/pptag_spec.rb +51 -0
- data/spec/inversion/template/publishtag_spec.rb +69 -0
- data/spec/inversion/template/subscribetag_spec.rb +60 -0
- data/spec/inversion/template/tag_spec.rb +97 -0
- data/spec/inversion/template/textnode_spec.rb +86 -0
- data/spec/inversion/template/unlesstag_spec.rb +84 -0
- data/spec/inversion/template/uriencodetag_spec.rb +49 -0
- data/spec/inversion/template/yieldtag_spec.rb +54 -0
- data/spec/inversion/template_spec.rb +269 -0
- data/spec/inversion/tilt_spec.rb +47 -0
- data/spec/inversion_spec.rb +95 -0
- data/spec/lib/constants.rb +9 -0
- data/spec/lib/helpers.rb +160 -0
- metadata +316 -0
- metadata.gz.sig +0 -0
@@ -0,0 +1,51 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# vim: set noet nosta sw=4 ts=4 :
|
3
|
+
|
4
|
+
require 'pathname'
|
5
|
+
require 'inversion/mixins'
|
6
|
+
require 'inversion/template/tag'
|
7
|
+
|
8
|
+
|
9
|
+
# Inversion 'yield' tag.
|
10
|
+
#
|
11
|
+
# A tag that yields to the block passed to Template#render (if there was one), and
|
12
|
+
# then inserts the resulting objects.
|
13
|
+
#
|
14
|
+
# == Example
|
15
|
+
#
|
16
|
+
# <?yield ?>
|
17
|
+
#
|
18
|
+
class Inversion::Template::YieldTag < Inversion::Template::Tag
|
19
|
+
include Inversion::Loggable
|
20
|
+
|
21
|
+
|
22
|
+
### Set up a YieldTag's instance variables.
|
23
|
+
def initialize( * )
|
24
|
+
@block_value = nil
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
######
|
29
|
+
public
|
30
|
+
######
|
31
|
+
|
32
|
+
### Rendering callback -- call the block before the template this tag
|
33
|
+
### belongs to is rendered.
|
34
|
+
def before_rendering( renderstate )
|
35
|
+
if renderstate.block
|
36
|
+
self.log.debug "Yielding to %p before rendering." % [ renderstate.block ]
|
37
|
+
@block_value = renderstate.block.call( renderstate )
|
38
|
+
self.log.debug " render block returned: %p" % [ @block_value ]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
### Render the YieldTag by returning what the #render block returned during
|
44
|
+
### #before_rendering (if there was a block).
|
45
|
+
def render( renderstate )
|
46
|
+
self.log.debug "Rendering as block return value: %p" % [ @block_value ]
|
47
|
+
return @block_value
|
48
|
+
end
|
49
|
+
|
50
|
+
end # class Inversion::Template::YieldTag
|
51
|
+
|
@@ -0,0 +1,82 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'tilt'
|
4
|
+
|
5
|
+
# Only add support if Tilt's already been loaded.
|
6
|
+
if defined?( ::Tilt )
|
7
|
+
|
8
|
+
# An adapter class for Tilt (https://github.com/rtomayko/tilt)
|
9
|
+
# :TODO: Add an example or two.
|
10
|
+
class Inversion::TiltWrapper < Tilt::Template
|
11
|
+
|
12
|
+
### Tilt::Template API: returns true if Inversion is loaded.
|
13
|
+
def self::engine_initialized?
|
14
|
+
return defined?( Inversion::Template )
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
### Tilt::Template API: lazy-load Inversion
|
19
|
+
def initialize_engine
|
20
|
+
require_template_library 'inversion'
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
### Tilt::Template API: load a template
|
25
|
+
def prepare
|
26
|
+
# Load the instance and set the path to the source
|
27
|
+
@template = Inversion::Template.new( self.data, self.options )
|
28
|
+
@template.source_file = self.file
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
### Hook the template's render phase.
|
33
|
+
def render( *args )
|
34
|
+
self.evaluate( *args )
|
35
|
+
end
|
36
|
+
|
37
|
+
### Tilt::Template API: render the template with the given +scope+, +locals+, and +block+.
|
38
|
+
def evaluate( scope, locals, &block )
|
39
|
+
@template.attributes.merge!( scope.to_h ) if scope.respond_to?( :to_h )
|
40
|
+
@template.attributes.merge!( locals )
|
41
|
+
|
42
|
+
return @template.render( &block )
|
43
|
+
end
|
44
|
+
|
45
|
+
end # class Inversion::TiltWrapper
|
46
|
+
|
47
|
+
# Also add #each to Inversion::Template so they can be returned from actions directly, too.
|
48
|
+
module Inversion::TemplateTiltAdditions
|
49
|
+
|
50
|
+
# TODO: Factor the common parts of this out in Inversion::Template so there's no
|
51
|
+
# duplication.
|
52
|
+
def each
|
53
|
+
self.log.info "rendering template 0x%08x (Sinatra-style)" % [ self.object_id/2 ]
|
54
|
+
state = Inversion::RenderState.new( nil, self.attributes, self.options )
|
55
|
+
|
56
|
+
# Pre-render hook
|
57
|
+
self.walk_tree {|node| node.before_rendering(state) }
|
58
|
+
|
59
|
+
self.log.debug " rendering node tree: %p" % [ @node_tree ]
|
60
|
+
self.walk_tree {|node| state << node }
|
61
|
+
|
62
|
+
# Post-render hook
|
63
|
+
self.walk_tree {|node| node.after_rendering(state) }
|
64
|
+
|
65
|
+
self.log.info " done rendering template 0x%08x" % [ self.object_id/2 ]
|
66
|
+
return state.destination.each do |node|
|
67
|
+
yield( node.to_s )
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end # module Inversion::TemplateTiltAdditions
|
72
|
+
|
73
|
+
# Add the mixin to Template
|
74
|
+
class Inversion::Template
|
75
|
+
include Inversion::TemplateTiltAdditions
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
Tilt.register( Inversion::TiltWrapper, 'tmpl', 'inversion' )
|
80
|
+
|
81
|
+
end
|
82
|
+
|
@@ -0,0 +1,235 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# vim: set nosta noet ts=4 sw=4:
|
3
|
+
|
4
|
+
require 'logger'
|
5
|
+
require 'erb'
|
6
|
+
|
7
|
+
require 'inversion' unless defined?( Inversion )
|
8
|
+
require 'inversion/mixins'
|
9
|
+
|
10
|
+
|
11
|
+
module Inversion
|
12
|
+
|
13
|
+
# :stopdoc:
|
14
|
+
|
15
|
+
# A alternate formatter for Logger instances.
|
16
|
+
class LogFormatter < Logger::Formatter
|
17
|
+
|
18
|
+
# The format to output unless debugging is turned on
|
19
|
+
DEFAULT_FORMAT = "[%1$s.%2$06d %3$d/%4$s] %5$5s -- %7$s\n"
|
20
|
+
|
21
|
+
# The format to output if debugging is turned on
|
22
|
+
DEFAULT_DEBUG_FORMAT = "[%1$s.%2$06d %3$d/%4$s] %5$5s {%6$s} -- %7$s\n"
|
23
|
+
|
24
|
+
|
25
|
+
### Initialize the formatter with a reference to the logger so it can check for log level.
|
26
|
+
def initialize( logger, format=DEFAULT_FORMAT, debug=DEFAULT_DEBUG_FORMAT ) # :notnew:
|
27
|
+
@logger = logger
|
28
|
+
@format = format
|
29
|
+
@debug_format = debug
|
30
|
+
|
31
|
+
super()
|
32
|
+
end
|
33
|
+
|
34
|
+
######
|
35
|
+
public
|
36
|
+
######
|
37
|
+
|
38
|
+
# The Logger object associated with the formatter
|
39
|
+
attr_accessor :logger
|
40
|
+
|
41
|
+
# The logging format string
|
42
|
+
attr_accessor :format
|
43
|
+
|
44
|
+
# The logging format string that's used when outputting in debug mode
|
45
|
+
attr_accessor :debug_format
|
46
|
+
|
47
|
+
|
48
|
+
### Log using either the DEBUG_FORMAT if the associated logger is at ::DEBUG level or
|
49
|
+
### using FORMAT if it's anything less verbose.
|
50
|
+
def call( severity, time, progname, msg )
|
51
|
+
args = [
|
52
|
+
time.strftime( '%Y-%m-%d %H:%M:%S' ), # %1$s
|
53
|
+
time.usec, # %2$d
|
54
|
+
Process.pid, # %3$d
|
55
|
+
Thread.current == Thread.main ? 'main' : Thread.object_id, # %4$s
|
56
|
+
severity, # %5$s
|
57
|
+
progname, # %6$s
|
58
|
+
msg # %7$s
|
59
|
+
]
|
60
|
+
|
61
|
+
if @logger.level == Logger::DEBUG
|
62
|
+
return self.debug_format % args
|
63
|
+
else
|
64
|
+
return self.format % args
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end # class LogFormatter
|
68
|
+
|
69
|
+
|
70
|
+
# A ANSI-colorized formatter for Logger instances.
|
71
|
+
class ColorLogFormatter < Logger::Formatter
|
72
|
+
|
73
|
+
# Set some ANSI escape code constants (Shamelessly stolen from Perl's
|
74
|
+
# Term::ANSIColor by Russ Allbery <rra@stanford.edu> and Zenin <zenin@best.com>
|
75
|
+
ANSI_ATTRIBUTES = {
|
76
|
+
'clear' => 0,
|
77
|
+
'reset' => 0,
|
78
|
+
'bold' => 1,
|
79
|
+
'dark' => 2,
|
80
|
+
'underline' => 4,
|
81
|
+
'underscore' => 4,
|
82
|
+
'blink' => 5,
|
83
|
+
'reverse' => 7,
|
84
|
+
'concealed' => 8,
|
85
|
+
|
86
|
+
'black' => 30, 'on_black' => 40,
|
87
|
+
'red' => 31, 'on_red' => 41,
|
88
|
+
'green' => 32, 'on_green' => 42,
|
89
|
+
'yellow' => 33, 'on_yellow' => 43,
|
90
|
+
'blue' => 34, 'on_blue' => 44,
|
91
|
+
'magenta' => 35, 'on_magenta' => 45,
|
92
|
+
'cyan' => 36, 'on_cyan' => 46,
|
93
|
+
'white' => 37, 'on_white' => 47
|
94
|
+
}
|
95
|
+
|
96
|
+
|
97
|
+
### Create a string that contains the ANSI codes specified and return it
|
98
|
+
def self::ansi_code( *attributes )
|
99
|
+
attributes.flatten!
|
100
|
+
attributes.collect! {|at| at.to_s }
|
101
|
+
return '' unless /(?:vt10[03]|xterm(?:-color)?|linux|screen)/i =~ ENV['TERM']
|
102
|
+
attributes = ANSI_ATTRIBUTES.values_at( *attributes ).compact.join(';')
|
103
|
+
|
104
|
+
if attributes.empty?
|
105
|
+
return ''
|
106
|
+
else
|
107
|
+
return "\e[%sm" % attributes
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
### Colorize the given +string+ with the specified +attributes+ and
|
113
|
+
### return it, handling line-endings, color reset, etc.
|
114
|
+
def self::colorize( *args )
|
115
|
+
string = ''
|
116
|
+
|
117
|
+
if block_given?
|
118
|
+
string = yield
|
119
|
+
else
|
120
|
+
string = args.shift
|
121
|
+
end
|
122
|
+
|
123
|
+
ending = string[/(\s)$/] || ''
|
124
|
+
string = string.rstrip
|
125
|
+
|
126
|
+
return self.ansi_code( args.flatten ) + string + self.ansi_code( 'reset' ) + ending
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
# Color settings
|
131
|
+
LEVEL_FORMATS = {
|
132
|
+
:debug => colorize( :bold, :black ) {"[%1$s.%2$06d %3$d/%4$s] %5$5s {%6$s} -- %7$s\n"},
|
133
|
+
:info => colorize( :normal ) {"[%1$s.%2$06d %3$d/%4$s] %5$5s -- %7$s\n"},
|
134
|
+
:warn => colorize( :bold, :yellow ) {"[%1$s.%2$06d %3$d/%4$s] %5$5s -- %7$s\n"},
|
135
|
+
:error => colorize( :red ) {"[%1$s.%2$06d %3$d/%4$s] %5$5s -- %7$s\n"},
|
136
|
+
:fatal => colorize( :bold, :red, :on_white ) {"[%1$s.%2$06d %3$d/%4$s] %5$5s -- %7$s\n"},
|
137
|
+
}
|
138
|
+
|
139
|
+
|
140
|
+
### Initialize the formatter with a reference to the logger so it can check for log level.
|
141
|
+
def initialize( logger, settings={} ) # :notnew:
|
142
|
+
settings = LEVEL_FORMATS.merge( settings )
|
143
|
+
|
144
|
+
@logger = logger
|
145
|
+
@settings = settings
|
146
|
+
|
147
|
+
super()
|
148
|
+
end
|
149
|
+
|
150
|
+
######
|
151
|
+
public
|
152
|
+
######
|
153
|
+
|
154
|
+
# The Logger object associated with the formatter
|
155
|
+
attr_accessor :logger
|
156
|
+
|
157
|
+
# The formats, by level
|
158
|
+
attr_accessor :settings
|
159
|
+
|
160
|
+
|
161
|
+
### Log using the format associated with the severity
|
162
|
+
def call( severity, time, progname, msg )
|
163
|
+
args = [
|
164
|
+
time.strftime( '%Y-%m-%d %H:%M:%S' ), # %1$s
|
165
|
+
time.usec, # %2$d
|
166
|
+
Process.pid, # %3$d
|
167
|
+
Thread.current == Thread.main ? 'main' : Thread.object_id, # %4$s
|
168
|
+
severity, # %5$s
|
169
|
+
progname, # %6$s
|
170
|
+
msg # %7$s
|
171
|
+
]
|
172
|
+
|
173
|
+
return self.settings[ severity.downcase.to_sym ] % args
|
174
|
+
end
|
175
|
+
|
176
|
+
end # class LogFormatter
|
177
|
+
|
178
|
+
|
179
|
+
# An alternate formatter for Logger instances that outputs +div+ HTML
|
180
|
+
# fragments.
|
181
|
+
class HtmlLogFormatter < Logger::Formatter
|
182
|
+
include ERB::Util # for html_escape()
|
183
|
+
|
184
|
+
# The default HTML fragment that'll be used as the template for each log message.
|
185
|
+
HTML_LOG_FORMAT = %q{
|
186
|
+
<div class="log-message %5$s">
|
187
|
+
<span class="log-time">%1$s.%2$06d</span>
|
188
|
+
[
|
189
|
+
<span class="log-pid">%3$d</span>
|
190
|
+
/
|
191
|
+
<span class="log-tid">%4$s</span>
|
192
|
+
]
|
193
|
+
<span class="log-level">%5$s</span>
|
194
|
+
:
|
195
|
+
<span class="log-name">%6$s</span>
|
196
|
+
<span class="log-message-text">%7$s</span>
|
197
|
+
</div>
|
198
|
+
}
|
199
|
+
|
200
|
+
### Override the logging formats with ones that generate HTML fragments
|
201
|
+
def initialize( logger, format=HTML_LOG_FORMAT ) # :notnew:
|
202
|
+
@logger = logger
|
203
|
+
@format = format
|
204
|
+
super()
|
205
|
+
end
|
206
|
+
|
207
|
+
|
208
|
+
######
|
209
|
+
public
|
210
|
+
######
|
211
|
+
|
212
|
+
# The HTML fragment that will be used as a format() string for the log
|
213
|
+
attr_accessor :format
|
214
|
+
|
215
|
+
|
216
|
+
### Return a log message composed out of the arguments formatted using the
|
217
|
+
### formatter's format string
|
218
|
+
def call( severity, time, progname, msg )
|
219
|
+
args = [
|
220
|
+
time.strftime( '%Y-%m-%d %H:%M:%S' ), # %1$s
|
221
|
+
time.usec, # %2$d
|
222
|
+
Process.pid, # %3$d
|
223
|
+
Thread.current == Thread.main ? 'main' : Thread.object_id, # %4$s
|
224
|
+
severity.downcase, # %5$s
|
225
|
+
progname, # %6$s
|
226
|
+
html_escape( msg ).gsub(/\n/, '<br />') # %7$s
|
227
|
+
]
|
228
|
+
|
229
|
+
return self.format % args
|
230
|
+
end
|
231
|
+
|
232
|
+
end # class HtmlLogFormatter
|
233
|
+
|
234
|
+
end # module Inversion
|
235
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
Hello, Sinatra!
|
@@ -0,0 +1,177 @@
|
|
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
|
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
|
+
|
16
|
+
require 'inversion/mixins'
|
17
|
+
|
18
|
+
|
19
|
+
describe Inversion, "mixins" do
|
20
|
+
|
21
|
+
describe Inversion::Loggable do
|
22
|
+
before(:each) do
|
23
|
+
@logfile = StringIO.new('')
|
24
|
+
Inversion.logger = Logger.new( @logfile )
|
25
|
+
|
26
|
+
@test_class = Class.new do
|
27
|
+
include Inversion::Loggable
|
28
|
+
|
29
|
+
def log_test_message( level, msg )
|
30
|
+
self.log.send( level, msg )
|
31
|
+
end
|
32
|
+
|
33
|
+
def logdebug_test_message( msg )
|
34
|
+
self.log_debug.debug( msg )
|
35
|
+
end
|
36
|
+
end
|
37
|
+
@obj = @test_class.new
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
it "is able to output to the log via its #log method" do
|
42
|
+
@obj.log_test_message( :debug, "debugging message" )
|
43
|
+
@logfile.rewind
|
44
|
+
@logfile.read.should =~ /debugging message/
|
45
|
+
end
|
46
|
+
|
47
|
+
it "is able to output to the log via its #log_debug method" do
|
48
|
+
@obj.logdebug_test_message( "sexydrownwatch" )
|
49
|
+
@logfile.rewind
|
50
|
+
@logfile.read.should =~ /sexydrownwatch/
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
describe Inversion::HashUtilities do
|
56
|
+
it "includes a function for stringifying Hash keys" do
|
57
|
+
testhash = {
|
58
|
+
:foo => 1,
|
59
|
+
:bar => {
|
60
|
+
:klang => 'klong',
|
61
|
+
:barang => { :kerklang => 'dumdumdum' },
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
result = Inversion::HashUtilities.stringify_keys( testhash )
|
66
|
+
|
67
|
+
result.should be_an_instance_of( Hash )
|
68
|
+
result.should_not be_equal( testhash )
|
69
|
+
result.should == {
|
70
|
+
'foo' => 1,
|
71
|
+
'bar' => {
|
72
|
+
'klang' => 'klong',
|
73
|
+
'barang' => { 'kerklang' => 'dumdumdum' },
|
74
|
+
}
|
75
|
+
}
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
it "includes a function for symbolifying Hash keys" do
|
80
|
+
testhash = {
|
81
|
+
'foo' => 1,
|
82
|
+
'bar' => {
|
83
|
+
'klang' => 'klong',
|
84
|
+
'barang' => { 'kerklang' => 'dumdumdum' },
|
85
|
+
}
|
86
|
+
}
|
87
|
+
|
88
|
+
result = Inversion::HashUtilities.symbolify_keys( testhash )
|
89
|
+
|
90
|
+
result.should be_an_instance_of( Hash )
|
91
|
+
result.should_not be_equal( testhash )
|
92
|
+
result.should == {
|
93
|
+
:foo => 1,
|
94
|
+
:bar => {
|
95
|
+
:klang => 'klong',
|
96
|
+
:barang => { :kerklang => 'dumdumdum' },
|
97
|
+
}
|
98
|
+
}
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
describe Inversion::AbstractClass do
|
105
|
+
|
106
|
+
context "mixed into a class" do
|
107
|
+
it "will cause the including class to hide its ::new method" do
|
108
|
+
testclass = Class.new { include Inversion::AbstractClass }
|
109
|
+
|
110
|
+
expect {
|
111
|
+
testclass.new
|
112
|
+
}.to raise_error( NoMethodError, /private/ )
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
context "mixed into a superclass" do
|
119
|
+
|
120
|
+
before(:each) do
|
121
|
+
testclass = Class.new {
|
122
|
+
include Inversion::AbstractClass
|
123
|
+
pure_virtual :test_method
|
124
|
+
}
|
125
|
+
subclass = Class.new( testclass )
|
126
|
+
@instance = subclass.new
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
it "raises a NotImplementedError when unimplemented API methods are called" do
|
131
|
+
expect {
|
132
|
+
@instance.test_method
|
133
|
+
}.to raise_error( NotImplementedError, /does not provide an implementation of/ )
|
134
|
+
end
|
135
|
+
|
136
|
+
it "declares the virtual methods so that they can be used with arguments under Ruby 1.9" do
|
137
|
+
expect {
|
138
|
+
@instance.test_method( :some, :arguments )
|
139
|
+
}.to raise_error( NotImplementedError, /does not provide an implementation of/ )
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
|
147
|
+
describe Inversion::Escaping do
|
148
|
+
|
149
|
+
before( :each ) do
|
150
|
+
objclass = Class.new do
|
151
|
+
include Inversion::Escaping
|
152
|
+
|
153
|
+
def render( state )
|
154
|
+
return self.escape( "<something>", state )
|
155
|
+
end
|
156
|
+
end
|
157
|
+
@obj = objclass.new
|
158
|
+
end
|
159
|
+
|
160
|
+
it "adds configurable escaping to including classes" do
|
161
|
+
render_state = Inversion::RenderState.new( {}, :escape_format => :html )
|
162
|
+
@obj.render( render_state ).should == "<something>"
|
163
|
+
end
|
164
|
+
|
165
|
+
it "doesn't escape anything if escaping is disabled" do
|
166
|
+
render_state = Inversion::RenderState.new( {}, :escape_format => nil )
|
167
|
+
@obj.render( render_state ).should == "<something>"
|
168
|
+
end
|
169
|
+
|
170
|
+
it "doesn't escape anything if escaping is set to ':none'" do
|
171
|
+
render_state = Inversion::RenderState.new( {}, :escape_format => :none )
|
172
|
+
@obj.render( render_state ).should == "<something>"
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
177
|
+
|