html-tag 2.0.0 → 3.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5c14a5d669505ed74d43e52cb564a8635a48a21670e0dce86756b3fc18a90a28
4
- data.tar.gz: 00c996b4444863bd710c722585b53638a28f562e64a79483335a853a7e4670e0
3
+ metadata.gz: 1af81083a15e78d8cecfed801fb466ce389ccae3bd5378528acc1f63aa345e3a
4
+ data.tar.gz: 668a8a601339fe419daba93f97c33df6f4d3c1ce391b6df6cb70d3cb5574f719
5
5
  SHA512:
6
- metadata.gz: 00eebf82a2b96e95f25272f536ada28d90115a2a177a129c5877a966449dc87de88833520eb9aa0e8d18038f06a9fd3bab079e10ae92c40be3479e4670787592
7
- data.tar.gz: 57047fe46f74f6bb2e6d400c1c0bbb4e9832fc631eabc43cd4f83070c7ccfa67d2a87c6a6c62e1b44db73d61ed3ce2b1fc17412f6a461616f37c349fc759b9b2
6
+ metadata.gz: d520970b6bfbeb1738e7dc23110f4c66e3859a98fbeb59876f9d31bd916f1b288bb72743da4b38bc944942880d92c4641cce873e1e8e57f82ac726dafacdacfa
7
+ data.tar.gz: fd4750d1cdbfe778a41a02371a3cca980956ec553acf66df3daf5b40a73c3249e22aceab0287e6f0ca3760da46d71befeb7d029d696d847abd786504bf1ada0a
data/.version CHANGED
@@ -1 +1 @@
1
- 2.0.0
1
+ 3.0.0
@@ -0,0 +1,31 @@
1
+ # Hash
2
+ unless {}.respond_to?(:tag)
3
+ class Hash
4
+ def tag node_name, inner_html=nil
5
+ ::HtmlTag::Outbound.build node_name, self, inner_html
6
+ end
7
+ end
8
+ end
9
+
10
+ # String
11
+ unless ''.respond_to?(:tag)
12
+ class String
13
+ def tag node_name, opts={}
14
+ ::HtmlTag::Outbound.build node_name, opts, self
15
+ end
16
+ end
17
+ end
18
+
19
+ # HtmlTag do ...
20
+ def HtmlTag *args, &block
21
+ args[0] ||= :div
22
+
23
+ if args[0].class == Hash
24
+ args[1] = args[0]
25
+ args[0] = :div
26
+ end
27
+
28
+ out = HtmlTag::Inbound.new self
29
+ out.send(*args, &block)
30
+ out.render
31
+ end
@@ -1,18 +1,38 @@
1
1
  # inclue HtmlTag to import tag method
2
2
 
3
+ require 'set'
4
+
3
5
  module HtmlTag
4
6
  extend self
5
7
 
6
- def tag
7
- ::HtmlTagBuilder
8
+ ###
9
+
10
+ OPTS = {
11
+ format: false
12
+ }
13
+
14
+ TAGS ||= Set.new %i(
15
+ a b button code colgroup dd div dl dt em fieldset form h1 h2 h3 h4 h5 h6
16
+ header i iframe label legend li main map nav noscript object ol optgroup option p pre q
17
+ script section select small span strong summary table tbody td textarea tfoot th thead title tr u ul video
18
+ )
19
+
20
+ EMPTY_TAGS ||= Set.new %w(area base br col embed hr img input keygen link meta param source track wbr)
21
+
22
+ def tag *args, &block
23
+ if block
24
+ HtmlTag *args, &block
25
+ else
26
+ ::HtmlTag::Outbound
27
+ end
8
28
  end
9
29
 
10
30
  # forward to class only if
11
31
  def method_missing tag_name, *args, &block
12
32
  if self === HtmlTag
13
- ::HtmlTagBuilder.tag(tag_name, args[0], args[1], &block)
33
+ Outbound.tag(tag_name, args[0], args[1], &block)
14
34
  else
15
35
  super
16
36
  end
17
37
  end
18
- end
38
+ end
@@ -0,0 +1,180 @@
1
+ # improved builder that is not pasing node pointers
2
+
3
+ # HtmlTag do
4
+ # form do
5
+ # input name: q
6
+ # end
7
+ # end
8
+
9
+ module HtmlTag
10
+ class Inbound
11
+ IVARS ||= Struct.new :HtmlTagInboundIvars, :context, :data, :depth, :inbound
12
+
13
+ # allows to add cusom tags if needed
14
+ # HtmlTag::Inbound.define :foo
15
+ def self.define tag, empty: false
16
+ if empty
17
+ EMPTY_TAGS.add tag
18
+ end
19
+
20
+ define_method tag do |*args, &block|
21
+ tag tag, *args, &block
22
+ end
23
+ end
24
+
25
+ # create static methods for all common tags (method missing is slow)
26
+ (TAGS + EMPTY_TAGS).each {|tag| define tag }
27
+
28
+ ###
29
+
30
+ def initialize context
31
+ # copy all instance varialbes from context
32
+ for el in context.instance_variables
33
+ unless el.to_s.include?('@_')
34
+ val = context.instance_variable_get el
35
+ instance_variable_set el, val
36
+ end
37
+ end
38
+
39
+ # lets keep all instance vars in one object
40
+ @_iv = IVARS.new
41
+ @_iv.context = context
42
+ @_iv.data = []
43
+ @_iv.depth = 0
44
+ @_iv.inbound = true
45
+ end
46
+
47
+ # access parent context via parent / context / this
48
+ # h1 class: this.class_name
49
+ def parent &block
50
+ if block
51
+ @_iv.context.instance_exec(&block)
52
+ else
53
+ @_iv.context
54
+ end
55
+ end
56
+ alias :context :parent
57
+ alias :this :parent
58
+
59
+ # export renderd data
60
+ def render
61
+ @_iv.data
62
+ .join('')
63
+ .gsub(/\n+/, $/)
64
+ .gsub(/([\w>])[[:blank:]]+</, '\1<')
65
+ end
66
+
67
+ # render single node
68
+ def tag name, *args, &block
69
+ opt_hash, opt_data = _prepare_tag_params args
70
+
71
+ tag_data = "%s%s<%s" % [_depth_new_line, _depth_spaces, name]
72
+
73
+ # if tag params given, add them
74
+ if opt_hash
75
+ tag_data += ' '
76
+ tag_data += opt_hash.inject([]) do |t, el|
77
+ key, value = el
78
+
79
+ case value
80
+ when Array
81
+ value = value.join(' ')
82
+ when Hash
83
+ for el in value
84
+ t.push '%s-%s="%s"' % [key, el[0], _escape_param(el[1])]
85
+ end
86
+ else
87
+ t.push '%s="%s"' % [key, _escape_param(value)]
88
+ end
89
+ t
90
+ end.join(' ')
91
+ end
92
+
93
+ unless EMPTY_TAGS.include?(name)
94
+ tag_data += '>'
95
+ end
96
+
97
+ @_iv.data << tag_data
98
+
99
+ # nested blocks
100
+ if block
101
+ @_iv.depth += 1
102
+ instance_exec(@_iv.context, &block)
103
+ # block.call(self) # for outbound render
104
+ @_iv.depth -= 1
105
+ end
106
+
107
+ if EMPTY_TAGS.include?(name)
108
+ @_iv.data << ' />'
109
+ else
110
+ unless opt_data
111
+ @_iv.data << _depth_spaces
112
+ end
113
+
114
+ @_iv.data << '%s</%s>%s' % [opt_data, name, _depth_new_line]
115
+ end
116
+ end
117
+
118
+ def push data
119
+ @_iv.data << data
120
+ end
121
+
122
+ def method_missing name, *args, &block
123
+ klass = name.to_s
124
+
125
+ if klass.start_with?('_')
126
+ # _foo__bar-baz class: 'dux' -> <div class="foo bar-baz dux"></div>
127
+ classes = klass
128
+ .sub('_', '')
129
+ .split('__')
130
+ .map{|it| it.gsub('_', '-') }
131
+ .join(' ')
132
+
133
+ prepared = _prepare_tag_params args
134
+
135
+ prepared[0] ||= {}
136
+ prepared[0][:class] = "#{classes} #{prepared[0][:class]}".sub(/\s+$/, '')
137
+
138
+ tag :div, *prepared, &block
139
+ else
140
+ message = [
141
+ %{HTML tag "#{name}" not found.},
142
+ "Use this.#{name}() to call method in parent context",
143
+ "or use tag(:#{name}, params, data) to add custom html node."
144
+ ]
145
+ raise NoMethodError.new(message.join(' '))
146
+ end
147
+ end
148
+
149
+ private
150
+
151
+ def _prepare_tag_params args
152
+ opt_hash, opt_data = args
153
+
154
+ # allow any arragement of vars
155
+ # div class: :foo, 123
156
+ # div 123, class: :foo
157
+ if opt_hash && opt_hash.class != Hash
158
+ opt_hash, opt_data = opt_data, opt_hash
159
+ end
160
+
161
+ [opt_hash, opt_data]
162
+ end
163
+
164
+ def _depth_spaces
165
+ if OPTS[:format]
166
+ ' ' * 2 * @_iv.depth
167
+ else
168
+ ''
169
+ end
170
+ end
171
+
172
+ def _depth_new_line
173
+ OPTS[:format] ? $/ : ''
174
+ end
175
+
176
+ def _escape_param el
177
+ el.to_s.gsub(/"/, '&quot;')
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,127 @@
1
+ module HtmlTag
2
+ class Outbound
3
+ class << self
4
+ # tag.div -> tag.tag :div
5
+ def method_missing name, *args, &block
6
+ tag name, args[0], args[1], &block
7
+ end
8
+
9
+ # tag :div, { 'class'=>'iform' } do
10
+ def tag name, *args
11
+ data, opts =
12
+ if args[1]
13
+ args[0].class == Hash ? args.reverse : args
14
+ elsif args[0]
15
+ if args[0].class == Symbol
16
+ # tag.div(:a) { 1 } -> <div class="a">1</div>
17
+ [nil, { class: args[0].to_s.gsub('__', ' ').gsub('_', '-') }]
18
+ elsif args[0].class == Hash
19
+ [nil, args[0]]
20
+ else
21
+ [args[0], {}]
22
+ end
23
+ else
24
+ [nil, {}]
25
+ end
26
+
27
+ opts ||= {}
28
+
29
+ unless opts.class == Hash
30
+ raise ArgumentError.new('HtmlTag: bad agrument, attributes are no a hash')
31
+ end
32
+
33
+ if data.class == Hash
34
+ raise ArgumentError.new('HtmlTag: bad agrument, data sent as hash')
35
+ end
36
+
37
+ # covert n._row_foo to n(class: 'row-foo')
38
+ name = name.to_s
39
+ if name.to_s[0, 1] == '_'
40
+ classes = name
41
+ .sub('_', '')
42
+ .split('__')
43
+ .map{|it| it.gsub('_', '-') }
44
+ .join(' ')
45
+
46
+ opts ||= {}
47
+ opts[:class] = "#{classes} #{opts[:class]}".sub(/\s+$/, '')
48
+ name = :div
49
+ end
50
+
51
+ if block_given?
52
+ if data
53
+ raise ArgumentError.new('HtmlTag: data is allreay defined and block is given')
54
+ end
55
+
56
+ stack = new
57
+ data = yield(stack, opts)
58
+
59
+ # if data is pushed to passed node, use that data
60
+ data = stack.data if stack.data.first
61
+ end
62
+
63
+ data = data.join('') if data.is_a?(Array)
64
+
65
+ build name, opts, data
66
+ end
67
+
68
+ # build html node
69
+ def build node, attrs={}, text=nil
70
+ node = node.to_s
71
+
72
+ opts = []
73
+ attrs.each do |attr_key, attr_value|
74
+ if attr_value.is_a?(Hash)
75
+ for data_key, data_value in attr_value
76
+ __add_opts opts, "#{attr_key}-#{data_key}", data_value
77
+ end
78
+ else
79
+ __add_opts opts, attr_key, attr_value
80
+ end
81
+ end
82
+
83
+ opts = opts.first ? ' '+opts.join(' ') : ''
84
+
85
+ if node
86
+ text ||= '' unless EMPTY_TAGS.include?(node)
87
+ text ? %{<#{node}#{opts}>#{text}</#{node}>} : %{<#{node}#{opts} />}
88
+ else
89
+ opts
90
+ end
91
+ end
92
+
93
+ # tag.div(class: 'klasa') do -> tag.('klasa') do
94
+ def call class_name, &block
95
+ tag(:div, class_name, &block)
96
+ end
97
+
98
+ def __add_opts opts, key, value
99
+ unless value.to_s == ''
100
+ value = value.join(' ') if value.is_a?(Array)
101
+ key = key.to_s.gsub(/data_/,'data-')
102
+ opts.push key+'="'+value.to_s.gsub(/"/,'&quot;')+'"'
103
+ end
104
+ end
105
+ end
106
+
107
+ ###
108
+
109
+ attr_reader :data
110
+
111
+ def initialize
112
+ @data = []
113
+ end
114
+
115
+ # push data to stack
116
+ def push data=nil
117
+ @data.push block_given? ? yield : data
118
+ end
119
+
120
+ private
121
+
122
+ # forward to class
123
+ def method_missing tag_name, *args, &block
124
+ @data.push self.class.tag(tag_name, args[0], args[1], &block)
125
+ end
126
+ end
127
+ end
data/lib/html-tag.rb CHANGED
@@ -1,3 +1,5 @@
1
- require_relative './html-tag/html_tag_builder'
2
1
  require_relative './html-tag/html_tag'
3
- require_relative './html-tag/adapter'
2
+ require_relative './html-tag/outbound'
3
+ require_relative './html-tag/inbound'
4
+ require_relative './html-tag/globals'
5
+
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: html-tag
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dino Reic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-27 00:00:00.000000000 Z
11
+ date: 2022-07-29 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Fast and powerful tag builder, upgrade to Rails tag helper, framework
14
14
  agnostic.
@@ -19,9 +19,10 @@ extra_rdoc_files: []
19
19
  files:
20
20
  - "./.version"
21
21
  - "./lib/html-tag.rb"
22
- - "./lib/html-tag/adapter.rb"
22
+ - "./lib/html-tag/globals.rb"
23
23
  - "./lib/html-tag/html_tag.rb"
24
- - "./lib/html-tag/html_tag_builder.rb"
24
+ - "./lib/html-tag/inbound.rb"
25
+ - "./lib/html-tag/outbound.rb"
25
26
  homepage: https://github.com/dux/html-tag
26
27
  licenses:
27
28
  - MIT
@@ -41,7 +42,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
41
42
  - !ruby/object:Gem::Version
42
43
  version: '0'
43
44
  requirements: []
44
- rubygems_version: 3.0.6
45
+ rubygems_version: 3.2.3
45
46
  signing_key:
46
47
  specification_version: 4
47
48
  summary: HTML tag builder
@@ -1,17 +0,0 @@
1
- # Hash
2
- unless {}.respond_to?(:tag)
3
- class Hash
4
- def tag node_name, inner_html=nil
5
- ::HtmlTagBuilder.build node_name, self, inner_html
6
- end
7
- end
8
- end
9
-
10
- # String
11
- unless ''.respond_to?(:tag)
12
- class String
13
- def tag node_name, opts={}
14
- ::HtmlTagBuilder.build node_name, opts, self
15
- end
16
- end
17
- end
@@ -1,124 +0,0 @@
1
- require 'set'
2
-
3
- class HtmlTagBuilder
4
- EMPTY_TAGS ||= Set.new %w(area base br col embed hr img input keygen link meta param source track wbr)
5
-
6
- class << self
7
- # tag.div -> tag.tag :div
8
- def method_missing name, *args, &block
9
- tag name, args[0], args[1], &block
10
- end
11
-
12
- # tag :div, { 'class'=>'iform' } do
13
- def tag name, *args
14
- data, opts =
15
- if args[1]
16
- args[0].class == Hash ? args.reverse : args
17
- elsif args[0]
18
- if args[0].class == Symbol
19
- # tag.div(:a) { 1 } -> <div class="a">1</div>
20
- [nil, { class: args[0].to_s.gsub('__', ' ').gsub('_', '-') }]
21
- elsif args[0].class == Hash
22
- [nil, args[0]]
23
- else
24
- [args[0], {}]
25
- end
26
- else
27
- [nil, {}]
28
- end
29
-
30
- opts ||= {}
31
-
32
- unless opts.class == Hash
33
- raise ArgumentError.new('HtmlTag: bad agrument, attriobutes are no a hash')
34
- end
35
-
36
- if data.class == Hash
37
- raise ArgumentError.new('HtmlTag: bad agrument, data sent as hash')
38
- end
39
-
40
- # covert n._row_foo to n(class: 'row-foo')
41
- name = name.to_s
42
- if name.to_s[0, 1] == '_'
43
- opts ||= {}
44
- opts[:class] = name.to_s.sub('_', '').gsub('_', '-')
45
- name = :div
46
- end
47
-
48
- if block_given?
49
- if data
50
- raise ArgumentError.new('HtmlTag: data is allreay defined and block is given')
51
- end
52
-
53
- stack = new
54
- data = yield(stack, opts)
55
-
56
- # if data is pushed to passed node, use that data
57
- data = stack.data if stack.data.first
58
- end
59
-
60
- data = data.join('') if data.is_a?(Array)
61
-
62
- build name, opts, data
63
- end
64
-
65
- # build html node
66
- def build node, attrs={}, text=nil
67
- node = node.to_s
68
-
69
- opts = []
70
- attrs.each do |attr_key, attr_value|
71
- if attr_value.is_a?(Hash)
72
- for data_key, data_value in attr_value
73
- __add_opts opts, "#{attr_key}-#{data_key}", data_value
74
- end
75
- else
76
- __add_opts opts, attr_key, attr_value
77
- end
78
- end
79
-
80
- opts = opts.first ? ' '+opts.join(' ') : ''
81
-
82
- if node
83
- text ||= '' unless EMPTY_TAGS.include?(node)
84
- out = text ? %{<#{node}#{opts}>#{text}</#{node}>} : %{<#{node}#{opts} />}
85
- out.respond_to?(:html_safe) ? out.html_safe : out
86
- else
87
- opts
88
- end
89
- end
90
-
91
- # tag.div(class: 'klasa') do -> tag.('klasa') do
92
- def call class_name, &block
93
- tag(:div, class_name, &block)
94
- end
95
-
96
- def __add_opts opts, key, value
97
- unless value.to_s == ''
98
- value = value.join(' ') if value.is_a?(Array)
99
- key = key.to_s.gsub(/data_/,'data-')
100
- opts.push key+'="'+value.to_s.gsub(/"/,'&quot;')+'"'
101
- end
102
- end
103
- end
104
-
105
- ###
106
-
107
- attr_reader :data
108
-
109
- def initialize
110
- @data = []
111
- end
112
-
113
- # push data to stack
114
- def push data=nil
115
- @data.push block_given? ? yield : data
116
- end
117
-
118
- private
119
-
120
- # forward to class
121
- def method_missing tag_name, *args, &block
122
- @data.push self.class.tag(tag_name, args[0], args[1], &block)
123
- end
124
- end