html-native 0.1.0 → 0.2.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: 2ec4658fd7a7e2a040535c411ca661cc80291d705b59099c93b6eecd184fb35e
4
- data.tar.gz: e96476a674a70ad4e28ba9ab223057bbc3bbdcab00ae91d1ff39c1788e383131
3
+ metadata.gz: f4e5910254a0afad80152339f40b75051ac6045ab51b95f3a0cfd44c6d9d9c81
4
+ data.tar.gz: a291bbadcb69cb44f067c7c17c01a39b542f8f9bfaebceb95f1b76731c6bbbef
5
5
  SHA512:
6
- metadata.gz: 85deca5f040b4268a9b3cf533483f2fbe91de270e5b6dbaf35817cea6363e49e008863481d24eea85c9c18123715caf21cfbe08f2f2c872cd844866ab95c956f
7
- data.tar.gz: 7eca06fcf63a3159af0e2de5c4502ad5d969707de4c3f0221df07ca73b9d0b49e224edae049d8c6a5f59c1f390664c56221c9b74bc499ee4e213817c100ac6e6
6
+ metadata.gz: 27da9d8f7a378e0a2eff7b989fae29f8ab04b000715542f87906ecda76cae0b4dd31a82fd3fab4e3dd50ca64954efd64727ac3d4bdbda13d497d6c3cffcba7d4
7
+ data.tar.gz: 846abdea65fb7711610a9a22a5b80c85527fc67c34af386924af7b4092bd32e41a0b1587eef4ff26a8d13c1949801dd4e4e18274ba99f8a7b5aea046b06a1658
@@ -3,13 +3,6 @@ require "html-native/builder"
3
3
 
4
4
  module HTMLComponent
5
5
 
6
- # Excluded currently because it makes checking in `Builder` ugly
7
- # Makes `include` and `extend` work exactly the same.
8
- # It's a dirty hack based on laziness, and strict use of `extend` is preferred.
9
- # def self.included(base)
10
- # base.extend(self)
11
- # end
12
-
13
6
  # Generates generation methods for each HTML5-valid tag. These methods have the
14
7
  # name of the tag. Note that this interferes with the builtin `p` method.
15
8
  TAG_LIST.each do |tag|
@@ -24,6 +17,10 @@ module HTMLComponent
24
17
  end
25
18
  end
26
19
 
20
+ # Creates a module that encompasses the given block in an HTMLComponent
21
+ # context. This gives access to methods in the block as though the block was
22
+ # declared as the `render` function in a module extending HTMLComponent
23
+ # (pretty much because it is).
27
24
  def self.singleton(&block)
28
25
  Module.new do
29
26
  extend HTMLComponent
@@ -2,6 +2,11 @@ require "html-native"
2
2
  require "html-native/builder"
3
3
 
4
4
  module Enumerable
5
+ # Maps the given block to each element of *enum*. The result of each iteration
6
+ # is added to an HTMLComponent::Builder instance, which is returned after the
7
+ # final iteration.
8
+ #
9
+ # If no block is given, an enumerator is returned instead.
5
10
  def component_map
6
11
  if block_given?
7
12
  result = HTMLComponent::Builder.new
@@ -14,134 +19,276 @@ module Enumerable
14
19
  end
15
20
  end
16
21
 
22
+ # Returns an OrderedListComponent representing the *enum*.
23
+ #
24
+ # See OrderedListComponent#new for details on how to apply attributes.
17
25
  def to_ol(attributes: {})
18
26
  OrderedListComponent.new(self, attributes: attributes)
19
27
  end
20
28
 
29
+ # Returns an UnorderedListComponent representing the *enum*.
30
+ #
31
+ # See UnorderedListComponent#new for details on how to apply attributes.
21
32
  def to_ul(attributes: {})
22
33
  UnorderedListComponent.new(self, attributes: attributes)
23
34
  end
24
35
  end
25
36
 
37
+ # OrderedListComponent represents an HTML ordered list based on an Enumerable
38
+ # collection.
39
+ #
40
+ # Attributes in an OrderedListComponent are separated into multiple groups since
41
+ # there are multiple kinds of tags. These groups are:
42
+ # - list - The attributes associated with the <ol> element
43
+ # - item - The attributes associated with <li> elements
44
+ #
45
+ # For example, to have a list with 20px padding and the class of "list-item"
46
+ # given to each item, you could write:
47
+ # ```
48
+ # OrderedListComponent.new(data, attributes:
49
+ # {list: {style: "padding: 20px"}, item: {class: "list-item"}})
50
+ #
51
+ # ```
52
+ # which is equivalent to
53
+ # ```
54
+ # <ol style="padding: 20px">
55
+ # <li class="list-item">...</li>
56
+ # <li class="list-item">...</li>
57
+ # ...
58
+ # </ol>
59
+ # ```
26
60
  class OrderedListComponent
27
61
  include HTMLComponent
28
62
 
29
- def initialize(data, attributes: {})
63
+ # Creates a new instance of OrderedListComponent from the values of *data*.
64
+ #
65
+ # If a block is given, each item in *data* is passed to it to render the list
66
+ # items. If no block is given, *data* are used directly.
67
+ def initialize(data, attributes: {}, &block)
30
68
  @list_data = data
31
69
  @list_attributes = attributes[:list] || {}
32
70
  @item_attributes = attributes[:item] || {}
71
+ @block = block
33
72
  end
34
73
 
35
- def render(&block)
74
+ # Converts the OrderedListComponent instance to the equivalent HTML.
75
+ #
76
+ # *render* can be called directly, but that usually isn't necessary.
77
+ # HTMLComponent::Builder handles this automatically, so it only needs to be
78
+ # done if there is no prior instance of one.
79
+ def render
36
80
  ol(@list_attributes) do
37
81
  @list_data.component_map do |l|
38
82
  li(@item_attributes) do
39
- block_given? ? yield(l) : l.to_s
83
+ @block ? @block.call(l) : l
40
84
  end
41
85
  end
42
86
  end
43
87
  end
44
88
  end
45
89
 
90
+ # UnorderedListComponent represents an HTML unordered list generated from an
91
+ # Enumerable collection.
92
+ #
93
+ # Attributes in an UnorderedListComponent are separated into multiple groups since
94
+ # there are multiple kinds of tags. These groups are:
95
+ # - list - The attributes associated with the <ul> element
96
+ # - item - The attributes associated with <li> elements
97
+ #
98
+ # For example, to have a list with 20px padding and the class of "list-item"
99
+ # given to each item, you could write:
100
+ # ```
101
+ # UnorderedListComponent.new(data, attributes:
102
+ # {list: {style: "padding: 20px"}, item: {class: "list-item"}})
103
+ #
104
+ # ```
105
+ # which is equivalent to
106
+ # ```
107
+ # <ul style="padding: 20px">
108
+ # <li class="list-item">...</li>
109
+ # <li class="list-item">...</li>
110
+ # ...
111
+ # </ul>
112
+ # ```
46
113
  class UnorderedListComponent
47
114
  include HTMLComponent
48
115
 
49
- def initialize(data, attributes: {})
116
+ # Creates a new instance of UnorderedListComponent from the values of *data*.
117
+ #
118
+ # If a block is given, each item in *data* is passed to it to render the list
119
+ # items. If no block is given, *data* are used directly.
120
+ def initialize(data, attributes: {}, &block)
50
121
  @list_data = data
51
122
  @list_attributes = attributes[:list] || {}
52
123
  @item_attributes = attributes[:item] || {}
124
+ @block = block
53
125
  end
54
126
 
55
- def render(&block)
127
+ # Converts the UnorderedListComponent instance to the equivalent HTML.
128
+ #
129
+ # *render* can be called directly, but that usually isn't necessary.
130
+ # HTMLComponent::Builder handles this automatically, so it only needs to be
131
+ # done if there is no prior instance of one.
132
+ def render
56
133
  ul(@list_attributes) do
57
134
  @list_data.component_map do |l|
58
135
  li(@item_attributes) do
59
- block_given? ? yield(l) : l.to_s
136
+ @block ? @block.call(l) : l
60
137
  end
61
138
  end
62
139
  end
63
140
  end
64
141
  end
65
142
 
143
+ # ListComponent represents an HTML list based on an Enumerable collection.
144
+ #
145
+ # Attributes in an ListComponent are separated into multiple groups since
146
+ # there are multiple kinds of tags. These groups are:
147
+ # - list - The attributes associated with the <ul> element
148
+ # - item - The attributes associated with <li> elements
149
+ #
150
+ # For example, to have an ordered list with 20px padding and the class of
151
+ # "list-item" given to each item, you could write:
152
+ # ```
153
+ # ListComponent.new(data, ordered: true, attributes:
154
+ # {list: {style: "padding: 20px"}, item: {class: "list-item"}})
155
+ #
156
+ # ```
157
+ # which is equivalent to
158
+ # ```
159
+ # <ol style="padding: 20px">
160
+ # <li class="list-item">...</li>
161
+ # <li class="list-item">...</li>
162
+ # ...
163
+ # </ol>
164
+ # ```
66
165
  class ListComponent
67
- def initialize(data, attributes: {}, ordered: false)
68
- @list = ordered ? OrderedListComponent.new(data, attributes) :
69
- UnorderedListComponent.new(data, attributes)
166
+ # Creates a new instance of ListComponent from the values of *data*.
167
+ #
168
+ # This list can be either ordered or unordered, depending on *ordered* parameter.
169
+ # If *ordered* is true, the list will be ordered, otherwise it will be unordered.
170
+ # *ordered* is false by default.
171
+ #
172
+ # If a block is given, each item in *data* is passed to it to render the list
173
+ # items. If no block is given, *data* are used directly.
174
+ def initialize(data, attributes: {}, ordered: false, &block)
175
+ @list = ordered ? OrderedListComponent.new(data, attributes, &block) :
176
+ UnorderedListComponent.new(data, attributes, &block)
70
177
  end
71
178
 
72
- def render(&block)
73
- @list.render(&block)
179
+ # Converts the ListComponent instance to the equivalent HTML.
180
+ #
181
+ # *render* can be called directly, but that usually isn't necessary.
182
+ # HTMLComponent::Builder handles this automatically, so it only needs to be
183
+ # done if there is no prior instance of one.
184
+ def render
185
+ @list.render
74
186
  end
75
187
  end
76
188
 
189
+ # TableRowComponent represents an HTML table row generated from an
190
+ # Enumerable collection.
191
+ #
192
+ # Attributes in an TableRowComponent are separated into multiple groups since
193
+ # there are multiple kinds of tags. These groups are:
194
+ # - row - The attributes associated with the <tr> element
195
+ # - cell - The attributes associated with <td> elements
196
+ #
197
+ # For example, to have a row with 20px padding and the class of "table-cell"
198
+ # given to each cell, you could write:
199
+ # ```
200
+ # TableRowComponent.new(data, attributes:
201
+ # {row: {style: "padding: 20px"}, cell: {class: "list-item"}})
202
+ #
203
+ # ```
204
+ # which is equivalent to
205
+ # ```
206
+ # <tr style="padding: 20px">
207
+ # <td class="list-item">...</td>
208
+ # <td class="list-item">...</td>
209
+ # ...
210
+ # </tr>
211
+ # ```
77
212
  class TableRowComponent
78
213
  include HTMLComponent
79
214
 
80
- def initialize(data, attributes: {})
215
+ # Creates a new instance of TableRowComponent from the values of *data*.
216
+ #
217
+ # If a block is given, each item in *data* is passed to it to render the row
218
+ # cells. If no block is given, *data* are used directly.
219
+ def initialize(data, attributes: {}, &block)
81
220
  @data = data
82
221
  @row_attributes = attributes[:row] || {}
83
222
  @cell_attributes = attributes[:cell] || {}
223
+ @block = block
84
224
  end
85
225
 
86
- def render(&block)
226
+ # Converts the TableRowComponent instance to the equivalent HTML.
227
+ #
228
+ # *render* can be called directly, but that usually isn't necessary.
229
+ # HTMLComponent::Builder handles this automatically, so it only needs to be
230
+ # done if there is no prior instance of one.
231
+ def render
87
232
  tr(@row_attributes) do
88
233
  @data.component_map do |c|
89
- td(@cell_attributes) {block_given? ? yield(c) : c}
234
+ td(@cell_attributes) {@block ? @block.call(c) : c}
90
235
  end
91
236
  end
92
237
  end
93
238
  end
94
239
 
95
- # This needs some reworking, since it's not intuitive
240
+ # TableComponent represents an HTML table generated from an Enumerable
241
+ # collection.
242
+ #
243
+ # Attributes in an TableComponent are separated into multiple groups since
244
+ # there are multiple kinds of tags. These groups are:
245
+ # - table - The attributes associated with the <table> element.
246
+ # - header - The attributes associated with <tr> element representing the header.
247
+ # - header_cell - The attributes associated with <th> elements.
248
+ # - row - The attributes associated with all <tr> elements, including the header.
249
+ # - cell - The attributes associated with <td> and <th> elements.
250
+ #
251
+ # Refer to other components for the format for applying attributes.
96
252
  class TableComponent
97
253
  include HTMLComponent
98
254
 
99
- def initialize(header, rows, attributes: {})
100
- @header = header
101
- @rows = rows
255
+ # Creates a new instance of TableComponent from the values of *rows*.
256
+ #
257
+ # *rows* is an Enumerable collection of Enumerable objects.
258
+ #
259
+ # If a block is given, each item in *rows* is passed to it to render the table
260
+ # cells, not including the header. If no block is given, *rows* is used directly.
261
+ def initialize(rows, col_names: [], row_names: [], attributes: {}, &block)
262
+ @rows = rows.map(&:to_a)
263
+ @header = col_names.to_a
264
+ row_names = row_names.to_a
265
+ unless row_names.empty?
266
+ row_names.each_with_index do |name, i|
267
+ if i < @rows.size
268
+ @rows[i].prepend(name)
269
+ else
270
+ @rows << [name]
271
+ end
272
+ end
273
+ end
274
+ @header.prepend("") unless row_names.empty? || @header.empty?
275
+
102
276
  @table_attributes = attributes[:table] || {}
103
277
  @header_attributes = attributes[:header] || {}
104
278
  @header_cell_attributes = attributes[:header_cell] || {}
105
279
  @row_attributes = attributes[:row] || {}
106
280
  @cell_attributes = attributes[:cell] || {}
281
+ @block = block
107
282
  end
108
283
 
109
- # header options:
110
- # array - use as header
111
- # symbol - if :from_data, then use first row, if :none, set @header to nil
112
- def self.from_array(data, attributes: {}, header: :none)
113
- head = rows = nil
114
- if header == :from_data
115
- head = data[0]
116
- rows = data[1..]
117
- else
118
- head = header.kind_of?(Array) ? header : nil
119
- rows = data
120
- end
121
- new(head, rows, attributes: attributes)
122
- end
123
-
124
- def self.from_hash(data, attributes: {}, vertical: true)
125
- if vertical
126
- rowcount = data.values.map(&:length).max
127
- rows = [] * rowcount
128
- data.each do |k,col|
129
- rowcount.times do |i|
130
- rows[i] << (i < col.size ? col[i] : nil)
131
- end
132
- end
133
- new(data.keys, rows, attributes: attributes)
134
- else
135
- rows = data.map do |k, v|
136
- [k] + v
137
- end
138
- new(nil, rows, attributes: attributes)
139
- end
140
- end
141
-
142
- def render(&block)
284
+ # Converts the TableComponent instance to the equivalent HTML.
285
+ #
286
+ # *render* can be called directly, but that usually isn't necessary.
287
+ # HTMLComponent::Builder handles this automatically, so it only needs to be
288
+ # done if there is no prior instance of one.
289
+ def render
143
290
  table(@table_attributes) do
144
- if @header
291
+ unless @header.empty?
145
292
  tr(@row_attributes.merge(@header_attributes)) do
146
293
  @header.component_map do |h|
147
294
  th(@cell_attributes.merge(@header_cell_attributes)) {h}
@@ -151,47 +298,87 @@ class TableComponent
151
298
  Builder.new
152
299
  end +
153
300
  @rows.component_map do |row|
154
- TableRowComponent.new(row, attributes: {row: @row_attributes, cell: @cell_attributes}).render(&block)
301
+ attributes = {row: @row_attributes, cell: @cell_attributes}
302
+ TableRowComponent.new(row, attributes: attributes, &@block)
155
303
  end
156
304
  end
157
305
  end
158
306
  end
159
307
 
308
+ # DropdownComponent represents an HTML table row generated from an
309
+ # Enumerable collection.
310
+ #
311
+ # Attributes in an DropdownComponent are separated into multiple groups since
312
+ # there are multiple kinds of tags. These groups are:
313
+ # - menu - The attributes associated with the <select> element
314
+ # - item - The attributes associated with <option> elements
160
315
  class DropdownComponent
161
316
  include HTMLComponent
162
317
 
163
- def initialize(choices, name, attributes: {})
318
+ # Creates a new instance of DropdownComponent from the values of *choices*.
319
+ #
320
+ # If a block is given, each item in *choices* is passed to it to render the
321
+ # item. If no block is given, *choices* is used directly.
322
+ def initialize(choices, name, attributes: {}, &block)
164
323
  @choices = choices
165
324
  @name = name
166
325
  @menu_attributes = attributes[:menu]
167
326
  @item_attributes = attributes[:item]
327
+ @block = block
168
328
  end
169
329
 
170
- def render(&block)
330
+ # Converts the DropdownComponent instance to the equivalent HTML.
331
+ #
332
+ # *render* can be called directly, but that usually isn't necessary.
333
+ # HTMLComponent::Builder handles this automatically, so it only needs to be
334
+ # done if there is no prior instance of one.
335
+ def render
171
336
  select(@menu_attributes.merge({name: @name, id: "#{@name}-dropdown"})) do
172
337
  @choices.component_map do |c|
173
- option(@item_attributes.merge({value: c})) {block_given? ? yield(c) : c}
338
+ option(@item_attributes.merge({value: c})) {@block ? @block.call(c) : c}
174
339
  end
175
340
  end
176
341
  end
177
342
  end
178
343
 
344
+ # RadioGroupComponent represents an HTML radio button group generated from an
345
+ # Enumerable collection.
346
+ #
347
+ # Each item has a unique id of the form of `"#{name}-{choice}"`, where name is
348
+ # the provided *name* option, and choice is value of that button.
349
+ #
350
+ # Each item produces a button and a label.
351
+ #
352
+ # Attributes in an RadioGroupComponent are separated into multiple groups since
353
+ # there are multiple kinds of tags. These groups are:
354
+ # - button - The attributes associated with the <input type: "radio"> elements.
355
+ # - label - The attributes associated with <label> elements.
179
356
  class RadioGroupComponent
180
357
  include HTMLComponent
181
358
 
182
- def initialize(choices, name, attributes: {}, labelled: true)
359
+ # Creates a new instance of RadioGroupComponent from the values of *choices*.
360
+ #
361
+ # If a block is given, each item in *choices* is passed to it to render the
362
+ # label. If no block is given, *choices* is used directly.
363
+ def initialize(choices, name, attributes: {}, labelled: true, &block)
183
364
  @choices = choices
184
365
  @name = name
185
366
  @button_attributes = attributes[:button]
186
367
  @label_attributes = attributes[:label]
187
368
  @labelled = labelled
369
+ @block = block
188
370
  end
189
371
 
190
- def render(&block)
372
+ # Converts the RadioGroupComponent instance to the equivalent HTML.
373
+ #
374
+ # *render* can be called directly, but that usually isn't necessary.
375
+ # HTMLComponent::Builder handles this automatically, so it only needs to be
376
+ # done if there is no prior instance of one.
377
+ def render
191
378
  @choices.component_map do |c|
192
379
  id = "#{@name}-#{c}"
193
380
  input({type: "radio", id: id, name: @name, value: c}) +
194
- (@labelled ? (label({for: id}) {block_given? ? yield(c) : c}) : nil)
381
+ (@labelled ? (label({for: id}) {@block ? @block.call(c) : c}) : nil)
195
382
  end
196
383
  end
197
384
  end
@@ -1,4 +1,6 @@
1
1
  module HTMLComponent
2
+ # A list of all valid HTML5 elements. These are used to generate generator
3
+ # methods within HTMLComponent contexts.
2
4
  TAG_LIST = [
3
5
  :html,
4
6
  :base, :head, :link, :meta, :style, :title,
@@ -19,12 +21,12 @@ module HTMLComponent
19
21
  :option, :output, :progress, :select, :textarea,
20
22
  :details, :dialog, :menu, :summary,
21
23
  :slot, :template
22
- ] + (1..6).map{|i| :"h#{i}"}
23
-
24
- def self.tags
25
- TAG_LIST.dup
26
- end
24
+ ]
27
25
 
26
+ # A list of all limited attributes in HTML5. Any attribute not listed here are
27
+ # free to use in any element, as long as it is not in FORBIDDEN_ATTRIBUTES.
28
+ #
29
+ # Any attributes listed here will only be allowed in the associated elements.
28
30
  LIMITED_ATTRIBUTES = {
29
31
  accept: [:form, :input],
30
32
  "accept-charset": [:form],
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: html-native
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kellen Watt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-01-25 00:00:00.000000000 Z
11
+ date: 2021-01-26 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: An html generation DSL designed for fluid code creation.
14
14
  email: