hammer_builder 0.2.0 → 0.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.
- data/README.md +1 -4
- data/lib/hammer_builder/abstract.rb +35 -11
- data/lib/hammer_builder/abstract/abstract_double_tag.rb +67 -71
- data/lib/hammer_builder/abstract/abstract_single_tag.rb +1 -1
- data/lib/hammer_builder/abstract/abstract_tag.rb +45 -39
- data/lib/hammer_builder/doc.rb +100 -104
- data/lib/hammer_builder/dynamic_classes.rb +11 -4
- data/lib/hammer_builder/formatted.rb +6 -6
- data/lib/hammer_builder/strings_injector.rb +43 -0
- data/spec/hammer_builder_spec.rb +22 -15
- metadata +58 -47
- data/lib/hammer_builder/strings.rb +0 -29
data/lib/hammer_builder/doc.rb
CHANGED
@@ -3,6 +3,10 @@ module HammerBuilder
|
|
3
3
|
class AbstractTag
|
4
4
|
|
5
5
|
|
6
|
+
def self.strings_injector
|
7
|
+
dynamic_class_base.strings_injector
|
8
|
+
end
|
9
|
+
|
6
10
|
class_attribute :_attributes, :instance_writer => false, :instance_reader => false
|
7
11
|
self._attributes = []
|
8
12
|
|
@@ -58,11 +62,11 @@ module HammerBuilder
|
|
58
62
|
name = attribute.name.to_s
|
59
63
|
case attribute.type
|
60
64
|
when :string
|
61
|
-
|
62
|
-
"@output <<
|
65
|
+
strings_injector.add "attr_#{name}", " #{name.gsub('_', '-')}=#{@_str_quote}"
|
66
|
+
"@output << @_str_attr_#{name} << CGI.escapeHTML(content.to_s) << @_str_quote"
|
63
67
|
when :boolean
|
64
|
-
|
65
|
-
"@output <<
|
68
|
+
strings_injector.add "attr_#{name}", " #{name.gsub('_', '-')}=#{@_str_quote}#{name}#{@_str_quote}"
|
69
|
+
"@output << @_str_attr_#{name} if content"
|
66
70
|
end
|
67
71
|
end
|
68
72
|
|
@@ -87,11 +91,13 @@ module HammerBuilder
|
|
87
91
|
@stack = builder.instance_eval { @_stack }
|
88
92
|
@classes = []
|
89
93
|
@tag_name = self.rclass.tag_name
|
94
|
+
|
95
|
+
self.rclass.strings_injector.inject_to self
|
90
96
|
end
|
91
97
|
|
92
98
|
# @api private
|
93
99
|
def open(attributes = nil)
|
94
|
-
@output <<
|
100
|
+
@output << @_str_lt << @tag_name
|
95
101
|
@builder.current = self
|
96
102
|
attributes(attributes)
|
97
103
|
default
|
@@ -103,7 +109,7 @@ module HammerBuilder
|
|
103
109
|
# @param [#to_s] value
|
104
110
|
def attribute(name, value)
|
105
111
|
return __send__(name, value) if respond_to?(name)
|
106
|
-
@output <<
|
112
|
+
@output << @_str_space << name.to_s << @_str_eql_quote << CGI.escapeHTML(value.to_s) << @_str_quote
|
107
113
|
self
|
108
114
|
end
|
109
115
|
|
@@ -131,28 +137,26 @@ module HammerBuilder
|
|
131
137
|
data_attribute = /^data_([a-z_]+)$/
|
132
138
|
METHOD_MISSING_REGEXP = /#{data_attribute}|#{id_class}/ unless defined? METHOD_MISSING_REGEXP
|
133
139
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
self.__send__($3 == '!' ? :id : :class, $2)
|
144
|
-
end
|
145
|
-
else
|
146
|
-
super(method, *args, &block)
|
147
|
-
end
|
140
|
+
# allows data-* attributes and id, classes by method_missing
|
141
|
+
def method_missing(method, *args, &block)
|
142
|
+
method = method.to_s
|
143
|
+
if method =~ METHOD_MISSING_REGEXP
|
144
|
+
if $1
|
145
|
+
self.rclass.add_attributes Data::Attribute.new(method, :string)
|
146
|
+
self.send method, *args
|
147
|
+
else
|
148
|
+
self.__send__($3 == '!' ? :id : :class, $2)
|
148
149
|
end
|
150
|
+
else
|
151
|
+
super(method, *args, &block)
|
152
|
+
end
|
153
|
+
end
|
149
154
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
RUBY
|
155
|
+
#def respond_to?(symbol, include_private = false)
|
156
|
+
# symbol.to_s =~ METHOD_MISSING_REGEXP || super(symbol, include_private)
|
157
|
+
#end
|
154
158
|
|
155
|
-
|
159
|
+
strings_injector.add "attr_class", " class=#{strings_injector[:quote]}"
|
156
160
|
# adds classes to the tag by joining +classes+ with ' ' and skipping non-true classes
|
157
161
|
# @param [Array<#to_s>] classes
|
158
162
|
# @example
|
@@ -162,14 +166,13 @@ module HammerBuilder
|
|
162
166
|
self
|
163
167
|
end
|
164
168
|
|
165
|
-
|
169
|
+
strings_injector.add "attr_id", " id=#{strings_injector[:quote]}"
|
166
170
|
# adds id to the tag by joining +values+ with '_'
|
167
171
|
# @param [Array<#to_s>] values
|
168
172
|
# @example
|
169
173
|
# id('user', 12) #=> id="user_15"
|
170
174
|
def id(*values)
|
171
|
-
@output <<
|
172
|
-
Strings::QUOTE
|
175
|
+
@output << @_str_attr_id << CGI.escapeHTML(values.select { |v| v }.join(@_str_underscore)) << @_str_quote
|
173
176
|
self
|
174
177
|
end
|
175
178
|
|
@@ -222,7 +225,7 @@ module HammerBuilder
|
|
222
225
|
# @api private
|
223
226
|
def flush_classes
|
224
227
|
unless @classes.empty?
|
225
|
-
@output <<
|
228
|
+
@output << @_str_attr_class << CGI.escapeHTML(@classes.join(@_str_space)) << @_str_quote
|
226
229
|
@classes.clear
|
227
230
|
end
|
228
231
|
end
|
@@ -235,7 +238,7 @@ module HammerBuilder
|
|
235
238
|
# closes the tag
|
236
239
|
def flush
|
237
240
|
flush_classes
|
238
|
-
@output <<
|
241
|
+
@output << @_str_slash_gt
|
239
242
|
nil
|
240
243
|
end
|
241
244
|
end
|
@@ -243,55 +246,50 @@ module HammerBuilder
|
|
243
246
|
|
244
247
|
nil
|
245
248
|
|
246
|
-
#
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
def initialize(builder)
|
252
|
-
super
|
253
|
-
@content = nil
|
254
|
-
end
|
249
|
+
# @api private
|
250
|
+
def initialize(builder)
|
251
|
+
super
|
252
|
+
@content = nil
|
253
|
+
end
|
255
254
|
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
end
|
267
|
-
else
|
268
|
-
super(method, *args, &block)
|
269
|
-
end
|
255
|
+
# allows data-* attributes and id, classes by method_missing
|
256
|
+
def method_missing(method, *args, &block)
|
257
|
+
method = method.to_s
|
258
|
+
if method =~ METHOD_MISSING_REGEXP
|
259
|
+
if $1
|
260
|
+
self.rclass.add_attributes Data::Attribute.new(method.to_sym, :string)
|
261
|
+
self.send method, *args, &block
|
262
|
+
else
|
263
|
+
self.content(args[0]) if args[0]
|
264
|
+
self.__send__($3 == '!' ? :id : :class, $2, &block)
|
270
265
|
end
|
266
|
+
else
|
267
|
+
super(method, *args, &block)
|
268
|
+
end
|
269
|
+
end
|
271
270
|
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
RUBY
|
271
|
+
# @api private
|
272
|
+
def open(*args, &block)
|
273
|
+
attributes = if args.last.is_a?(Hash)
|
274
|
+
args.pop
|
275
|
+
end
|
276
|
+
content args[0]
|
277
|
+
super attributes
|
278
|
+
@stack << @tag_name
|
279
|
+
if block
|
280
|
+
with &block
|
281
|
+
else
|
282
|
+
self
|
283
|
+
end
|
284
|
+
end
|
287
285
|
|
288
286
|
# @api private
|
289
287
|
# closes the tag
|
290
288
|
def flush
|
291
289
|
flush_classes
|
292
|
-
@output <<
|
290
|
+
@output << @_str_gt
|
293
291
|
@output << CGI.escapeHTML(@content) if @content
|
294
|
-
@output <<
|
292
|
+
@output << @_str_slash_lt << @stack.pop << @_str_gt
|
295
293
|
@content = nil
|
296
294
|
end
|
297
295
|
|
@@ -314,7 +312,7 @@ module HammerBuilder
|
|
314
312
|
# end # => <div id="id">content</div>
|
315
313
|
def with
|
316
314
|
flush_classes
|
317
|
-
@output <<
|
315
|
+
@output << @_str_gt
|
318
316
|
@content = nil
|
319
317
|
@builder.current = nil
|
320
318
|
yield
|
@@ -322,37 +320,35 @@ module HammerBuilder
|
|
322
320
|
# @output << EscapeUtils.escape_html(content)
|
323
321
|
#end
|
324
322
|
@builder.flush
|
325
|
-
@output <<
|
323
|
+
@output << @_str_slash_lt << @stack.pop << @_str_gt
|
326
324
|
nil
|
327
325
|
end
|
328
326
|
|
329
327
|
alias_method :w, :with
|
330
328
|
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
end
|
329
|
+
def mimic(obj, &block)
|
330
|
+
super(obj, &nil)
|
331
|
+
return with(&block) if block
|
332
|
+
self
|
333
|
+
end
|
337
334
|
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
335
|
+
def data(hash, &block)
|
336
|
+
super(hash, &nil)
|
337
|
+
return with(&block) if block
|
338
|
+
self
|
339
|
+
end
|
343
340
|
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
341
|
+
def attribute(name, value, &block)
|
342
|
+
super(name, value, &nil)
|
343
|
+
return with(&block) if block
|
344
|
+
self
|
345
|
+
end
|
349
346
|
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
RUBY
|
347
|
+
def attributes(attrs, &block)
|
348
|
+
super(attrs, &nil)
|
349
|
+
return with(&block) if block
|
350
|
+
self
|
351
|
+
end
|
356
352
|
|
357
353
|
protected
|
358
354
|
|
@@ -363,20 +359,20 @@ module HammerBuilder
|
|
363
359
|
|
364
360
|
if instance_methods.include?(attribute.name)
|
365
361
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
362
|
+
def #{name}(*args, &block)
|
363
|
+
super(*args, &nil)
|
364
|
+
return with(&block) if block
|
365
|
+
self
|
366
|
+
end
|
371
367
|
RUBY
|
372
368
|
else
|
373
369
|
content_rendering = attribute_content_rendering(attribute)
|
374
370
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
371
|
+
def #{name}(content#{' = true' if attribute.type == :boolean}, &block)
|
372
|
+
#{content_rendering}
|
373
|
+
return with(&block) if block
|
374
|
+
self
|
375
|
+
end
|
380
376
|
RUBY
|
381
377
|
end
|
382
378
|
end
|
@@ -137,12 +137,19 @@ module HammerBuilder
|
|
137
137
|
DescribableClass
|
138
138
|
end
|
139
139
|
|
140
|
-
|
141
|
-
|
140
|
+
set_up_klass = lambda do |klass, description, block|
|
141
|
+
klass._description = description
|
142
|
+
klass.instance_variable_set :@dynamic_class_base, base
|
143
|
+
klass.singleton_class.send :attr_reader, :dynamic_class_base
|
144
|
+
klass.class_eval &block
|
145
|
+
end
|
146
|
+
|
147
|
+
klass = Class.new(superclass)
|
148
|
+
set_up_klass.call klass, "#{base}.dc[:#{klass_definition.name}]", klass_definition.definition
|
142
149
|
|
143
150
|
class_extensions(name).each do |klass_extension|
|
144
|
-
klass
|
145
|
-
|
151
|
+
klass = Class.new klass
|
152
|
+
set_up_klass.call klass, "#{base}.dc[:#{klass_extension.name}]", klass_extension.definition
|
146
153
|
end
|
147
154
|
|
148
155
|
@classes[name] = klass
|
@@ -8,7 +8,7 @@ module HammerBuilder
|
|
8
8
|
dynamic_classes do
|
9
9
|
extend_class :AbstractTag do
|
10
10
|
def open(attributes = nil)
|
11
|
-
@output <<
|
11
|
+
@output << @_str_newline << @_str_spaces.fetch(@stack.size, @_str_space) << @_str_lt << @tag_name
|
12
12
|
@builder.current = self
|
13
13
|
attributes(attributes)
|
14
14
|
default
|
@@ -19,7 +19,7 @@ module HammerBuilder
|
|
19
19
|
extend_class :AbstractDoubleTag do
|
20
20
|
def with
|
21
21
|
flush_classes
|
22
|
-
@output <<
|
22
|
+
@output << @_str_gt
|
23
23
|
@content = nil
|
24
24
|
@builder.current = nil
|
25
25
|
yield
|
@@ -27,8 +27,8 @@ module HammerBuilder
|
|
27
27
|
# @output << EscapeUtils.escape_html(content, false)
|
28
28
|
#end
|
29
29
|
@builder.flush
|
30
|
-
@output <<
|
31
|
-
@stack.pop <<
|
30
|
+
@output << @_str_newline << @_str_spaces.fetch(@stack.size-1, @_str_space) << @_str_slash_lt <<
|
31
|
+
@stack.pop << @_str_gt
|
32
32
|
nil
|
33
33
|
end
|
34
34
|
end
|
@@ -36,8 +36,8 @@ module HammerBuilder
|
|
36
36
|
|
37
37
|
def comment(comment)
|
38
38
|
flush
|
39
|
-
@_output <<
|
40
|
-
comment.to_s <<
|
39
|
+
@_output << @_str_newline << @_str_spaces.fetch(@_stack.size, @_str_space) << @_str_comment_start <<
|
40
|
+
comment.to_s << @_str_comment_end
|
41
41
|
end
|
42
42
|
end
|
43
43
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module HammerBuilder
|
2
|
+
class StringsInjector
|
3
|
+
|
4
|
+
attr_reader :strings, :objects_to_update
|
5
|
+
|
6
|
+
def initialize(&block)
|
7
|
+
@strings = Hash.new {|hash, key| raise ArgumentError "missing key #{key}" }
|
8
|
+
@objects_to_update = []
|
9
|
+
instance_eval &block
|
10
|
+
end
|
11
|
+
|
12
|
+
def [](name)
|
13
|
+
strings[name]
|
14
|
+
end
|
15
|
+
|
16
|
+
def add(name, value)
|
17
|
+
name = name.to_sym
|
18
|
+
raise "string #{name} is already set to #{value}" if strings.has_key?(name) && self[name] != value
|
19
|
+
replace name, value
|
20
|
+
end
|
21
|
+
|
22
|
+
def replace(name, value)
|
23
|
+
name = name.to_sym
|
24
|
+
strings[name] = value
|
25
|
+
update_objects name
|
26
|
+
end
|
27
|
+
|
28
|
+
def inject_to(obj)
|
29
|
+
@objects_to_update << obj
|
30
|
+
strings.keys.each { |name| update_object obj, name }
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def update_objects(name)
|
36
|
+
objects_to_update.each { |obj| update_object obj, name }
|
37
|
+
end
|
38
|
+
|
39
|
+
def update_object(obj, name)
|
40
|
+
obj.instance_variable_set(:"@_str_#{name}", self[name])
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/spec/hammer_builder_spec.rb
CHANGED
@@ -119,31 +119,38 @@ describe HammerBuilder do
|
|
119
119
|
|
120
120
|
it 'should render #id' do
|
121
121
|
quick_render { div.id :an_id }.should == '<div id="an_id"></div>'
|
122
|
-
quick_render { div.an_id! }.should == '<div id="
|
123
|
-
quick_render { div.an_id! { text 'content' } }.should == '<div id="
|
124
|
-
quick_render { div.an_id! 'content' }.should == '<div id="
|
125
|
-
quick_render { div.an_id! }.should == '<div id="
|
122
|
+
quick_render { div.an_id! }.should == '<div id="an-id"></div>'
|
123
|
+
quick_render { div.an_id! { text 'content' } }.should == '<div id="an-id">content</div>'
|
124
|
+
quick_render { div.an_id! 'content' }.should == '<div id="an-id">content</div>'
|
125
|
+
quick_render { div.an_id! }.should == '<div id="an-id"></div>'
|
126
126
|
quick_render { div :id => 12 }.should == '<div id="12"></div>'
|
127
127
|
quick_render { div 'asd', :id => 12 }.should == '<div id="12">asd</div>'
|
128
128
|
quick_render { hr.id 'an_id' }.should == '<hr id="an_id" />'
|
129
|
-
quick_render { hr.an_id! }.should == '<hr id="
|
129
|
+
quick_render { hr.an_id! }.should == '<hr id="an-id" />'
|
130
130
|
quick_render { hr :id => 'an_id' }.should == '<hr id="an_id" />'
|
131
131
|
|
132
|
-
quick_render { hr.id 'an', 'id', nil, false }.should == '<hr id="
|
133
|
-
quick_render { div.id 'an', 'id', nil, false }.should == '<div id="
|
132
|
+
quick_render { hr.id 'an', 'id', nil, false }.should == '<hr id="an-id" />'
|
133
|
+
quick_render { div.id 'an', 'id', nil, false }.should == '<div id="an-id"></div>'
|
134
|
+
|
135
|
+
quick_render { div.an_id! :class => 'big' }.should == '<div id="an-id" class="big"></div>'
|
136
|
+
quick_render { div.an_id!(:class => 'big') { text 'content' } }.should ==
|
137
|
+
'<div id="an-id" class="big">content</div>'
|
138
|
+
quick_render { div.an_id! 'content', :class => 'big' }.should == '<div id="an-id" class="big">content</div>'
|
139
|
+
quick_render { div.an_id! 'content' }.should == '<div id="an-id">content</div>'
|
140
|
+
quick_render { hr.an_id! :class => 'big' }.should == '<hr id="an-id" class="big" />'
|
134
141
|
end
|
135
142
|
|
136
143
|
it 'should render #class' do
|
137
144
|
#noinspection RubyArgCount
|
138
145
|
quick_render { div.class 'an_class' }.should == '<div class="an_class"></div>'
|
139
|
-
quick_render { div.an_class }.should == '<div class="
|
146
|
+
quick_render { div.an_class }.should == '<div class="an-class"></div>'
|
140
147
|
quick_render { div :class => 'an_class' }.should == '<div class="an_class"></div>'
|
141
148
|
#noinspection RubyArgCount
|
142
149
|
quick_render { hr.class 'an_class' }.should == '<hr class="an_class" />'
|
143
|
-
quick_render { hr.an_class }.should == '<hr class="
|
150
|
+
quick_render { hr.an_class }.should == '<hr class="an-class" />'
|
144
151
|
quick_render { hr :class => 'an_class' }.should == '<hr class="an_class" />'
|
145
152
|
|
146
|
-
quick_render { div.an_class.another_class }.should == '<div class="
|
153
|
+
quick_render { div.an_class.another_class }.should == '<div class="an-class another-class"></div>'
|
147
154
|
#noinspection RubyArgCount
|
148
155
|
quick_render { div.class 'an_class', 'another_class' }.should == '<div class="an_class another_class"></div>'
|
149
156
|
quick_render { div :class => ['an_class', 'another_class'] }.should == '<div class="an_class another_class"></div>'
|
@@ -159,7 +166,7 @@ describe HammerBuilder do
|
|
159
166
|
|
160
167
|
it '#[]' do
|
161
168
|
obj = Object.new
|
162
|
-
quick_render { div[obj] }.should == %Q(<div id="
|
169
|
+
quick_render { div[obj] }.should == %Q(<div id="object-#{obj.object_id}" class="object"></div>)
|
163
170
|
|
164
171
|
class AnObject
|
165
172
|
def self.hammer_builder_ref
|
@@ -178,11 +185,11 @@ describe HammerBuilder do
|
|
178
185
|
"an_id";
|
179
186
|
end
|
180
187
|
end)
|
181
|
-
quick_render { div[obj] }.should == %Q(<div id="
|
182
|
-
quick_render { div.mimic(obj) { text 'a' } }.should == %Q(<div id="
|
188
|
+
quick_render { div[obj] }.should == %Q(<div id="object-an_id" class="object"></div>)
|
189
|
+
quick_render { div.mimic(obj) { text 'a' } }.should == %Q(<div id="object-an_id" class="object">a</div>)
|
183
190
|
end
|
184
191
|
|
185
|
-
it "#data
|
192
|
+
it "#data-secret" do
|
186
193
|
quick_render { div('a').data_secret("I won't tell.") }.should == '<div data-secret="I won\'t tell.">a</div>'
|
187
194
|
end
|
188
195
|
|
@@ -240,7 +247,7 @@ describe HammerBuilder do
|
|
240
247
|
comment 'asd'
|
241
248
|
end
|
242
249
|
end.should == '<!DOCTYPE html>' + "\n" +
|
243
|
-
'<html xmlns="http://www.w3.org/1999/xhtml"><head><title id="
|
250
|
+
'<html xmlns="http://www.w3.org/1999/xhtml"><head><title id="an-id">a_title</title><meta charset="utf-8" />'+
|
244
251
|
'</head><body id="content">asd<div style="" class="left">asd<hr /></div><br /><div class="left"><hr />'+
|
245
252
|
'<script type="text/javascript">asd</script><script type="text/javascript"><![CDATA[asd]]></script>'+
|
246
253
|
'</div><!--asd--></body><!--asd--></html>'
|