inversion 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|