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 CHANGED
@@ -5,12 +5,9 @@ Fast Ruby xhtml5 renderer
5
5
  ## Links
6
6
 
7
7
  * **Presentation**: <http://hammer.pitr.ch/hammer_builder/presentation/presentation.html>
8
- * Gemcutter: <https://rubygems.org/gems/hammer_builder>
9
8
  * Github: <https://github.com/ruby-hammer/hammer-builder>
10
- * Yardoc: <http://rubydoc.info/github/ruby-hammer/hammer-builder/frames>
9
+ * Yardoc: <http://rubydoc.info/gems/hammer_builder/frames>
11
10
  * Issues: <https://github.com/ruby-hammer/hammer-builder/issues>
12
- * Changelog: <http://hammer.pitr.ch/hammer-builder/file.CHANGELOG.html>
13
- * Gem: [https://rubygems.org/gems/hammer_builder](https://rubygems.org/gems/hammer_builder)
14
11
  * Blog: <http://hammer.pitr.ch/>
15
12
 
16
13
  ## Syntax
@@ -3,7 +3,7 @@ require 'active_support/core_ext/class/attribute'
3
3
  require 'active_support/core_ext/string/inflections'
4
4
 
5
5
  require 'hammer_builder/dynamic_classes'
6
- require 'hammer_builder/strings'
6
+ require 'hammer_builder/strings_injector'
7
7
  require 'hammer_builder/data'
8
8
  require 'hammer_builder/data/html5'
9
9
  require "hammer_builder/pool"
@@ -19,6 +19,27 @@ module HammerBuilder
19
19
  require "hammer_builder/abstract/abstract_single_tag"
20
20
  require "hammer_builder/abstract/abstract_double_tag"
21
21
 
22
+ def self.strings_injector
23
+ @strings_injector ||= StringsInjector.new do
24
+ add :lt, '<'
25
+ add :gt, '>'
26
+ add :slash_lt, '</'
27
+ add :slash_gt, ' />'
28
+ add :dash, '-'
29
+ add :underscore, '_'
30
+ add :space, ' '
31
+ add :spaces, Array.new(300) { |i| (' ' * i).freeze }
32
+ add :newline, "\n"
33
+ add :quote, '"'
34
+ add :eql, '='
35
+ add :eql_quote, self[:eql] + self[:quote]
36
+ add :comment_start, '<!--'
37
+ add :comment_end, '-->'
38
+ add :cdata_start, '<![CDATA['
39
+ add :cdata_end, ']]>'
40
+ end
41
+ end
42
+
22
43
  # << faster then +
23
44
  # yield faster then block.call
24
45
  # accessing ivar and constant is faster then accesing hash or cvar
@@ -58,6 +79,9 @@ module HammerBuilder
58
79
  @_output = ""
59
80
  @_stack = []
60
81
  @_current = nil
82
+
83
+ self.class.strings_injector.inject_to self
84
+
61
85
  # tag classes initialization
62
86
  tags.each do |klass|
63
87
  instance_variable_set(:"@_#{klass}", self.class.dynamic_classes[klass.camelize.to_sym].new(self))
@@ -79,13 +103,13 @@ module HammerBuilder
79
103
  # inserts +comment+
80
104
  def comment(comment)
81
105
  flush
82
- @_output << Strings::COMMENT_START << comment.to_s << Strings::COMMENT_END
106
+ @_output << @_str_comment_start << comment.to_s << @_str_comment_end
83
107
  end
84
108
 
85
109
  # insersts CDATA with +content+
86
110
  def cdata(content)
87
111
  flush
88
- @_output << Strings::CDATA_START << content.to_s << Strings::CDATA_END
112
+ @_output << @_str_cdata_start << content.to_s << @_str_cdata_end
89
113
  end
90
114
 
91
115
  # renders html5 doc type
@@ -120,7 +144,7 @@ module HammerBuilder
120
144
  # @example
121
145
  # HammerBuilder::Formatted.new.go_in('asd') do |string|
122
146
  # div string
123
- # end.to_html! #=> "<div>asd</div>"
147
+ # end.to_html #=> "<div>asd</div>"
124
148
  #
125
149
  def go_in(*variables, &block)
126
150
  instance_exec *variables, &block
@@ -186,13 +210,13 @@ module HammerBuilder
186
210
  def join(collection, glue = nil, &it)
187
211
  # TODO as helper? two block method call #join(collection, &item).with(&glue)
188
212
  glue_block = case glue
189
- when String
190
- lambda { text glue }
191
- when Proc
192
- glue
193
- else
194
- lambda { }
195
- end
213
+ when String
214
+ lambda { text glue }
215
+ when Proc
216
+ glue
217
+ else
218
+ lambda { }
219
+ end
196
220
 
197
221
  collection.each_with_index do |obj, i|
198
222
  glue_block.call() if i > 0
@@ -5,55 +5,53 @@ module HammerBuilder
5
5
  def_class :AbstractDoubleTag, :AbstractTag do ###import
6
6
  nil
7
7
 
8
- # defined by class_eval because there is a error cased by super
9
- # super from singleton method that is defined to multiple classes is not supported;
10
- # this will be fixed in 1.9.3 or later (NotImplementedError)
11
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
12
- # @api private
13
- def initialize(builder)
14
- super
15
- @content = nil
16
- end
8
+ # @api private
9
+ def initialize(builder)
10
+ super
11
+ @content = nil
12
+ end
17
13
 
18
- # allows data-* attributes and id, classes by method_missing
19
- def method_missing(method, *args, &block)
20
- method = method.to_s
21
- if method =~ METHOD_MISSING_REGEXP
22
- if $1
23
- self.rclass.add_attributes Data::Attribute.new(method.to_sym, :string)
24
- self.send method, *args, &block
25
- else
26
- self.content(args[0]) if args[0]
27
- self.__send__($3 == '!' ? :id : :class, $2, &block)
28
- end
14
+ # allows data-* attributes and id, classes by method_missing
15
+ def method_missing(method, *args, &block)
16
+ method = method.to_s
17
+ if method =~ METHOD_MISSING_REGEXP
18
+ if $1
19
+ self.rclass.add_attributes Data::Attribute.new(method.to_sym, :string)
20
+ self.send method, *args, &block
29
21
  else
30
- super(method, *args, &block)
22
+ attributes(if args.last.is_a?(Hash)
23
+ args.pop
24
+ end)
25
+ content args.first
26
+ self.__send__($3 == '!' ? :id : :class, $2.gsub(@_str_underscore, @_str_dash), &block)
31
27
  end
28
+ else
29
+ super(method, *args, &block)
32
30
  end
31
+ end
33
32
 
34
- # @api private
35
- def open(*args, &block)
36
- attributes = if args.last.is_a?(Hash)
37
- args.pop
38
- end
39
- content args[0]
40
- super attributes
41
- @stack << @tag_name
42
- if block
43
- with &block
44
- else
45
- self
46
- end
33
+ # @api private
34
+ def open(*args, &block)
35
+ attributes = if args.last.is_a?(Hash)
36
+ args.pop
37
+ end
38
+ content args[0]
39
+ super attributes
40
+ @stack << @tag_name
41
+ if block
42
+ with &block
43
+ else
44
+ self
47
45
  end
48
- RUBY
46
+ end
49
47
 
50
48
  # @api private
51
49
  # closes the tag
52
50
  def flush
53
51
  flush_classes
54
- @output << Strings::GT
52
+ @output << @_str_gt
55
53
  @output << CGI.escapeHTML(@content) if @content
56
- @output << Strings::SLASH_LT << @stack.pop << Strings::GT
54
+ @output << @_str_slash_lt << @stack.pop << @_str_gt
57
55
  @content = nil
58
56
  end
59
57
 
@@ -76,7 +74,7 @@ module HammerBuilder
76
74
  # end # => <div id="id">content</div>
77
75
  def with
78
76
  flush_classes
79
- @output << Strings::GT
77
+ @output << @_str_gt
80
78
  @content = nil
81
79
  @builder.current = nil
82
80
  yield
@@ -84,37 +82,35 @@ module HammerBuilder
84
82
  # @output << EscapeUtils.escape_html(content)
85
83
  #end
86
84
  @builder.flush
87
- @output << Strings::SLASH_LT << @stack.pop << Strings::GT
85
+ @output << @_str_slash_lt << @stack.pop << @_str_gt
88
86
  nil
89
87
  end
90
88
 
91
89
  alias_method :w, :with
92
90
 
93
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
94
- def mimic(obj, &block)
95
- super(obj, &nil)
96
- return with(&block) if block
97
- self
98
- end
91
+ def mimic(obj, &block)
92
+ super(obj, &nil)
93
+ return with(&block) if block
94
+ self
95
+ end
99
96
 
100
- def data(hash, &block)
101
- super(hash, &nil)
102
- return with(&block) if block
103
- self
104
- end
97
+ def data(hash, &block)
98
+ super(hash, &nil)
99
+ return with(&block) if block
100
+ self
101
+ end
105
102
 
106
- def attribute(name, value, &block)
107
- super(name, value, &nil)
108
- return with(&block) if block
109
- self
110
- end
103
+ def attribute(name, value, &block)
104
+ super(name, value, &nil)
105
+ return with(&block) if block
106
+ self
107
+ end
111
108
 
112
- def attributes(attrs, &block)
113
- super(attrs, &nil)
114
- return with(&block) if block
115
- self
116
- end
117
- RUBY
109
+ def attributes(attrs, &block)
110
+ super(attrs, &nil)
111
+ return with(&block) if block
112
+ self
113
+ end
118
114
 
119
115
  protected
120
116
 
@@ -125,20 +121,20 @@ module HammerBuilder
125
121
 
126
122
  if instance_methods.include?(attribute.name)
127
123
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
128
- def #{name}(*args, &block)
129
- super(*args, &nil)
130
- return with(&block) if block
131
- self
132
- end
124
+ def #{name}(*args, &block)
125
+ super(*args, &nil)
126
+ return with(&block) if block
127
+ self
128
+ end
133
129
  RUBY
134
130
  else
135
131
  content_rendering = attribute_content_rendering(attribute)
136
132
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
137
- def #{name}(content#{' = true' if attribute.type == :boolean}, &block)
138
- #{content_rendering}
139
- return with(&block) if block
140
- self
141
- end
133
+ def #{name}(content#{' = true' if attribute.type == :boolean}, &block)
134
+ #{content_rendering}
135
+ return with(&block) if block
136
+ self
137
+ end
142
138
  RUBY
143
139
  end
144
140
  end
@@ -8,7 +8,7 @@ module HammerBuilder
8
8
  # closes the tag
9
9
  def flush
10
10
  flush_classes
11
- @output << Strings::SLASH_GT
11
+ @output << @_str_slash_gt
12
12
  nil
13
13
  end
14
14
  end ###import
@@ -3,6 +3,10 @@ module HammerBuilder
3
3
  dynamic_classes do
4
4
  def_class :AbstractTag do ###import
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,13 @@ module HammerBuilder
58
62
  name = attribute.name.to_s
59
63
  case attribute.type
60
64
  when :string
61
- Strings.add "attr_#{name}", " #{name.gsub('_', '-')}=\""
62
- "@output << Strings::ATTR_#{name.upcase} << CGI.escapeHTML(content.to_s) << Strings::QUOTE"
65
+ strings_injector.add "attr_#{name}", " #{name.gsub('_', '-')}=#{strings_injector[:quote]}"
66
+ "@output << @_str_attr_#{name} << CGI.escapeHTML(content.to_s) << @_str_quote"
63
67
  when :boolean
64
- Strings.add "attr_#{name}", " #{name.gsub('_', '-')}=\"#{name}\""
65
- "@output << Strings::ATTR_#{name.upcase} if content"
68
+ strings_injector.add(
69
+ "attr_#{name}",
70
+ " #{name.gsub('_', '-')}=#{strings_injector[:quote]}#{name}#{strings_injector[:quote]}")
71
+ "@output << @_str_attr_#{name} if content"
66
72
  end
67
73
  end
68
74
 
@@ -87,11 +93,13 @@ module HammerBuilder
87
93
  @stack = builder.instance_eval { @_stack }
88
94
  @classes = []
89
95
  @tag_name = self.rclass.tag_name
96
+
97
+ self.rclass.strings_injector.inject_to self
90
98
  end
91
99
 
92
100
  # @api private
93
101
  def open(attributes = nil)
94
- @output << Strings::LT << @tag_name
102
+ @output << @_str_lt << @tag_name
95
103
  @builder.current = self
96
104
  attributes(attributes)
97
105
  default
@@ -103,7 +111,7 @@ module HammerBuilder
103
111
  # @param [#to_s] value
104
112
  def attribute(name, value)
105
113
  return __send__(name, value) if respond_to?(name)
106
- @output << Strings::SPACE << name.to_s << Strings::EQL_QUOTE << CGI.escapeHTML(value.to_s) << Strings::QUOTE
114
+ @output << @_str_space << name.to_s << @_str_eql_quote << CGI.escapeHTML(value.to_s) << @_str_quote
107
115
  self
108
116
  end
109
117
 
@@ -131,28 +139,27 @@ module HammerBuilder
131
139
  data_attribute = /^data_([a-z_]+)$/
132
140
  METHOD_MISSING_REGEXP = /#{data_attribute}|#{id_class}/ unless defined? METHOD_MISSING_REGEXP
133
141
 
134
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
135
- # allows data-* attributes and id, classes by method_missing
136
- def method_missing(method, *args, &block)
137
- method = method.to_s
138
- if method =~ METHOD_MISSING_REGEXP
139
- if $1
140
- self.rclass.add_attributes Data::Attribute.new(method, :string)
141
- self.send method, *args
142
- else
143
- self.__send__($3 == '!' ? :id : :class, $2)
144
- end
142
+ # allows data-* attributes and id, classes by method_missing
143
+ def method_missing(method, *args, &block)
144
+ method = method.to_s
145
+ if method =~ METHOD_MISSING_REGEXP
146
+ if $1
147
+ self.rclass.add_attributes Data::Attribute.new(method, :string)
148
+ self.send method, *args
145
149
  else
146
- super(method, *args, &block)
150
+ self.__send__($3 == '!' ? :id : :class, $2.gsub(@_str_underscore, @_str_dash))
151
+ self.attributes args.first
147
152
  end
153
+ else
154
+ super(method, *args, &block)
148
155
  end
156
+ end
149
157
 
150
- #def respond_to?(symbol, include_private = false)
151
- # symbol.to_s =~ METHOD_MISSING_REGEXP || super(symbol, include_private)
152
- #end
153
- RUBY
158
+ #def respond_to?(symbol, include_private = false)
159
+ # symbol.to_s =~ METHOD_MISSING_REGEXP || super(symbol, include_private)
160
+ #end
154
161
 
155
- Strings.add "attr_class", " class=\""
162
+ strings_injector.add "attr_class", " class=#{strings_injector[:quote]}"
156
163
  # adds classes to the tag by joining +classes+ with ' ' and skipping non-true classes
157
164
  # @param [Array<#to_s>] classes
158
165
  # @example
@@ -162,14 +169,13 @@ module HammerBuilder
162
169
  self
163
170
  end
164
171
 
165
- Strings.add "attr_id", " id=\""
172
+ strings_injector.add "attr_id", " id=#{strings_injector[:quote]}"
166
173
  # adds id to the tag by joining +values+ with '_'
167
174
  # @param [Array<#to_s>] values
168
175
  # @example
169
- # id('user', 12) #=> id="user_15"
176
+ # id('user', 12) #=> id="user-15"
170
177
  def id(*values)
171
- @output << Strings::ATTR_ID << CGI.escapeHTML(values.select { |v| v }.join(Strings::UNDERSCORE)) <<
172
- Strings::QUOTE
178
+ @output << @_str_attr_id << CGI.escapeHTML(values.select { |v| v }.join(@_str_dash)) << @_str_quote
173
179
  self
174
180
  end
175
181
 
@@ -182,19 +188,19 @@ module HammerBuilder
182
188
  # div[AUser.new].with { text 'a' } # => <div id="a_user_1" class="a_user">a</div>
183
189
  def mimic(obj)
184
190
  klass = if obj.class.respond_to? :hammer_builder_ref
185
- obj.class.hammer_builder_ref
186
- else
187
- ActiveSupport::Inflector.underscore(obj.class.to_s).tr('/', '-')
188
- end
191
+ obj.class.hammer_builder_ref
192
+ else
193
+ ActiveSupport::Inflector.underscore(obj.class.to_s).tr('/', '-')
194
+ end
189
195
 
190
196
  id = case
191
- when obj.respond_to?(:hammer_builder_ref)
192
- obj.hammer_builder_ref
193
- when obj.respond_to?(:id)
194
- [klass, obj.id]
195
- else
196
- [klass, obj.object_id]
197
- end
197
+ when obj.respond_to?(:hammer_builder_ref)
198
+ obj.hammer_builder_ref
199
+ when obj.respond_to?(:id)
200
+ [klass, obj.id]
201
+ else
202
+ [klass, obj.object_id]
203
+ end
198
204
  #noinspection RubyArgCount
199
205
  self.class(klass).id(id)
200
206
  end
@@ -222,7 +228,7 @@ module HammerBuilder
222
228
  # @api private
223
229
  def flush_classes
224
230
  unless @classes.empty?
225
- @output << Strings::ATTR_CLASS << CGI.escapeHTML(@classes.join(Strings::SPACE)) << Strings::QUOTE
231
+ @output << @_str_attr_class << CGI.escapeHTML(@classes.join(@_str_space)) << @_str_quote
226
232
  @classes.clear
227
233
  end
228
234
  end