html-native 0.1.0 → 0.2.0

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