objective_elements 0.4.0 → 1.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: 853b8807d8ce1caddf258fb0bd4f023ec38157cffec51180d809d28d7a6c664d
4
- data.tar.gz: a8255aef5bece7857da7ccab4aa31f5aad1e0abd54f3376567057934a5d9ca9c
3
+ metadata.gz: c40decb6ef274c91eb3c04c8b88e3fe8cfebf9be34173044faa8541bee7e1a8c
4
+ data.tar.gz: c89f6d58e729c5a3a60095244fcdbcdb30b1f109214b0faf91b9b3c4fd27cf83
5
5
  SHA512:
6
- metadata.gz: de70f8907e7bf70b545a4b0eddac86ccae60690440cc36205db8376d0272035fcd3acd606bd0c90c5ed46d3f4cae0afb630d30b75c82350c939809a50f7ac229
7
- data.tar.gz: bce5362bede8ca1436db6f0d1f38c95a4d0f8b51bb2490c59b74458d43675541620636a9545733439cfd694118c041604f691b7910b3346b502a69ccaf143d86
6
+ metadata.gz: 7ba86d122bbacc96b7fa989cb122a63582cb9e6619a5e42777ed7eb69bf80b2837feca836c0f430c870a60c34e0f22906b10e808e1debd1c6ebe7f6b9ab6da56
7
+ data.tar.gz: 236c0aa5c7768d653ad702b63b66ffc2261416ac0cad3ba9bc404684f7428d41584468f9951b5967125f14b33000c26b5e79f7910dea6081e43f4879d03e65c7
data/README.md CHANGED
@@ -57,29 +57,42 @@ too, but hey! Now you don't have to. Here's a demo:
57
57
  ## Demo
58
58
 
59
59
  ```ruby
60
+ # gemfile:
61
+ gem 'objective_elements', '~>1.0.0'
62
+
63
+ # Anywhyere else:
64
+ require 'objective_elements'
65
+
60
66
  p = DoubleTag.new 'p'
61
67
  p.to_s
62
68
  # <p>
63
69
  # </p>
64
70
 
65
71
  # Add attributes as a hash. keys can be strings or symbols, values can be arrays or strings:
66
- p.add_attributes class: 'stumpy grumpy', 'id' => 'the-ugly-one'
72
+ p.attributes << { class: 'stumpy grumpy', 'id' => 'the-ugly-one' }
67
73
 
68
74
  # Add attributes as a string!
69
- p.add_attributes 'class="slimy" data-awesomeness="11"'
75
+ p.attributes << 'class="slimy" data-awesomeness="11"'
76
+
77
+ # Get attributes by calling a method!
78
+ p.data-awesomeness
79
+ # '11'
80
+
81
+ # Set them, too! (Note: This doesn't work for class or method)
82
+ p.id = 'killer'
70
83
 
71
84
  # Add content. It can be anything, or an array of anythings.
72
85
  p.add_content "Icky"
73
86
 
74
87
  p.to_s
75
- # <p class="stumpy grumpy slimy" id="the-ugly-one" data-awesomeness="11">
88
+ # <p class="stumpy grumpy slimy" id="killer" data-awesomeness="11">
76
89
  # Icky
77
90
  # </p>
78
91
 
79
92
  # Want a oneliner?
80
93
  p.oneline = true
81
94
  p.to_s
82
- # <p class="stumpy grumpy slimy" id="the-ugly-one" data-awesomeness="11">Icky</p>
95
+ # <p class="stumpy grumpy slimy" id="killer" data-awesomeness="11">Icky</p>
83
96
  p.oneline = false
84
97
 
85
98
  # Build a tag all at once:
@@ -93,11 +106,10 @@ p.add_content DoubleTag.new(
93
106
  # Add a parent tag:
94
107
  div = p.add_parent DoubleTag.new 'div'
95
108
 
96
- # Ruby implicitly calls .to_s on things when you try to perform string functions with them, so
97
- # this works:
109
+ # Implicit string conversion means cool stuff like this works:
98
110
  "#{div}"
99
111
  # <div>
100
- # <p class="stumpy mopey grumpy slimy" id="the-ugly-one" data-awesomeness="11">
112
+ # <p class="stumpy grumpy slimy" id="killer" data-awesomeness="11">
101
113
  # Icky
102
114
  # <a href="awesome-possum.com">Link!</a>
103
115
  # </p>
@@ -138,9 +150,40 @@ So we're on the same page, here's the terminology I'm using:
138
150
 
139
151
  ## Usage
140
152
 
141
- There are 2 classes: `SingleTag` is the base class, and `DoubleTag` inherits from it. A `SingleTag`
142
- is a self-closing tag, meaning it has no content and no closing tag. A `DoubleTag` is the other
143
- kind.
153
+ There are 2 classes you care about: `SingleTag` is the base class, and `DoubleTag` inherits from it.
154
+ A `SingleTag` is a self-closing tag, meaning it has no content and no closing tag. A `DoubleTag` is
155
+ the other kind.
156
+
157
+ ### Attributes
158
+ Attributes are their own class, and can be accessed by the `.attributes` method on both single and
159
+ double tags. Important methods:
160
+
161
+ ` << (attribute)` - Add new attributes, can accept a hash or a string. Hash keys will be converted
162
+ to symbols if they are not already, and values will be split on spaces into an array if they are not
163
+ already. Attributes can also be given as a string in the standard HTML syntax (`class="myclass"
164
+ id="my-id"`). **Every other method which adds attributes in some way, calls this method**. This
165
+ means that any time you are adding attributes, you can use any format which this method understands.
166
+
167
+ `.delete(attribute)` - Delete one or more attributes. Accepts a string, symbol, or an array of
168
+ strings and/or symbols.
169
+
170
+ `.replace(attribute)` - Replaces one or more attributes and values.
171
+
172
+ `.content[:attribute_name]` - Retrieve the content for a given attribute, as an array of strings.
173
+ Must be a symbol. You'll mostly need this when you don't know which attribute you need ahead of ti
174
+ me, or to access class and method attributes because you can't use the methods below:
175
+
176
+ `.content[:attribute_name] = ` - Don't do it. Use `<<` or `.replace`.
177
+
178
+ `.(attribute_name)` - Convenience method/syntactic sugar: Returns the value of a given attribute
179
+ name, as a space-separated string. This relies on method_missing, which means that any overlap with
180
+ already existing methods won't work. **You can't access `class` or `method` html attributes this
181
+ way, because basic objects in ruby already have those methods.**
182
+
183
+ `.(attribute_name) = value` - Same as above. Equivalent to `.replace(attribute)`. Interestingly,
184
+ `method = ` and `class = ` both work (`.class` is defined on the basic object class, but `.class=`
185
+ is not.). That said, you probably shouldn't use them because it will be confusing to understand
186
+ later.
144
187
 
145
188
  ### SingleTag Properties:
146
189
 
@@ -148,42 +191,36 @@ kind.
148
191
  - String
149
192
  - Mandatory
150
193
  - Which type of tag it is, such as 'hr' or 'img'
151
-
152
194
  #### attributes
153
- - Hash
154
- - Optional
155
- - Keys are stored as symbols, values are stored as arrays of strings: `{class: ['stumpy', 'slimy']}`
156
- - add them with `.add_attributes`, which can accept a few different formats.
195
+ - Instance of the class described above.
196
+
157
197
 
158
198
  ### SingleTag Methods (that you care about)
159
199
 
160
- `SingleTag.new(element, attributes: {})`
200
+ `SingleTag.new(element, attributes: nil)`
161
201
 
162
202
  `.to_s` - The big one. Returns your HTML as a string, nondestructively.
163
203
 
164
- `.add_attributes(new)` - The strongly recommended way to add new attributes. Can accept a hash (keys
165
- can be either symbols or strings, values can be either arrays or strings), or a string in the
166
- standard HTML syntax (`attribute="value" attribute2="value2 value3"`). Returns self.
167
-
168
- `.reset_attributes(new)` - Deletes all attributes, calls add_attributes on supplied argument if
169
- given.
170
-
171
- `.delete_attributes(keys)` - Accepts a single attribute, or an array of attributes (keys or
172
- strings), and deletes it.
173
-
174
- `.rewrite_attributes` - Accepts anything add_attributes understands, but replaces existing
175
- attributes instead of appending to them.
176
-
177
204
  `.add_parent(DoubleTag)` - returns supplied DoubleTag, with self added as a child.
178
205
 
206
+ `.attributes` - attr_reader for HTML attributes. This is how you can access any attribute method
207
+ described above.
208
+
209
+ `.reset_attributes` - Removes all attributes
179
210
 
211
+ `.attributes=(attributes)` - Sets attributes to the supplied argument
180
212
 
181
213
  `attr_reader :attributes`
182
214
  `attr_accessor :element`
183
215
 
216
+ `.(attribute_name)` / `.(attribute_name) = ` - Forwarded to attributes object. Allows you to set or
217
+ retrieve the value of attributes other than `class` and `method`, without having to type
218
+ `.attributes` in front of it.
219
+
184
220
  ### DoubleTag Properties:
185
221
 
186
- #### `DoubleTag` Inherits all of `SingleTag`'s properties and methods, and adds content and a closing tag.
222
+ #### `DoubleTag` Inherits all of `SingleTag`'s properties and methods, and adds content and a
223
+ closing tag.
187
224
 
188
225
  #### content
189
226
 
@@ -232,7 +269,7 @@ appropriate indentation applied, this is how you can get it.
232
269
 
233
270
  ```ruby
234
271
 
235
- require 'ojbective_elements'
272
+ require 'objective_elements'
236
273
 
237
274
  class MyDoubleTag < DoubleTag
238
275
  def indent
@@ -257,27 +294,31 @@ MyDoubleTag.new('p', content: 'hello').to_s
257
294
 
258
295
  ```html
259
296
 
297
+ <p>
260
298
  Here is some
261
299
  <strong>strong</strong>
262
300
  text.
301
+ </p>
263
302
 
264
303
  ```
265
304
  or this (default behavior):
266
305
 
267
306
  ```html
268
307
 
308
+ <p>
269
309
  Here is some
270
310
  <strong>
271
311
  strong
272
312
  </strong>
273
313
  text.
314
+ </p>
274
315
 
275
316
  ```
276
317
  But you can't do this without string interpolation or something:
277
318
 
278
319
  ```html
279
320
 
280
- Here is some <strong>strong</strong> text.
321
+ <p>Here is some <strong>strong</strong> text.</p>
281
322
 
282
323
  ```
283
324
  This doesn't affect how the browser will render it, but it might bug you if you're particular about
@@ -1,4 +1,5 @@
1
1
  module ObjectiveElements
2
2
  require_relative 'objective_elements/single_tag'
3
3
  require_relative 'objective_elements/double_tag'
4
+ require_relative 'objective_elements/html_attributes'
4
5
  end
@@ -1,44 +1,34 @@
1
1
  # Non-Self-Closing tag. Can have content, but doesn't have to.
2
2
  class DoubleTag < SingleTag
3
- attr_accessor :content, :oneline
4
- # content is an array of anything. Entries will be inserted sequentially in
5
- # between the opening and closing tags.
3
+ attr_accessor :oneline
4
+ attr_reader :content
6
5
 
7
- def initialize(element, attributes: nil, content: [], oneline: false)
6
+ # Content represents everything between the opening and closing tags.
7
+
8
+ def initialize(element, attributes: nil, content: nil, oneline: false)
8
9
  @oneline = oneline
9
- reset_content(content)
10
+ self.content = content
10
11
  super(element, attributes: attributes)
11
12
  end
12
13
 
13
- def closing_tag
14
- "</#{element}>"
14
+ def content=(new)
15
+ reset_content
16
+ add_content(new)
15
17
  end
16
18
 
17
- # Deletes all content, replaces with parameter (if supplied)
18
- def reset_content(new = nil)
19
+ def reset_content
19
20
  @content = []
20
- add_content(new) if new
21
- self
22
21
  end
23
22
 
24
23
  def add_content(addition)
25
- @content << addition
24
+ @content << addition if addition
26
25
  @content.flatten!
27
26
  self
28
27
  end
29
-
30
- def indent
31
- "\ \ "
32
- end
28
+ alias << add_content
33
29
 
34
30
  def to_a
35
- lines = content.map do |c|
36
- if c.is_a? SingleTag
37
- c.to_a
38
- else
39
- c.to_s.dup
40
- end
41
- end
31
+ lines = content.map { |c| build_content_line c }
42
32
  lines = lines.flatten.map { |l| l.prepend oneline ? '' : indent }
43
33
  lines.unshift(opening_tag).push(closing_tag)
44
34
  end
@@ -46,4 +36,18 @@ class DoubleTag < SingleTag
46
36
  def to_s
47
37
  to_a.join(oneline ? '' : "\n") + "\n"
48
38
  end
39
+
40
+ private
41
+
42
+ def build_content_line(element)
43
+ element.is_a?(SingleTag) ? element.to_a : element.to_s.dup
44
+ end
45
+
46
+ def indent
47
+ "\ \ "
48
+ end
49
+
50
+ def closing_tag
51
+ "</#{element}>"
52
+ end
49
53
  end
@@ -0,0 +1,108 @@
1
+ # Represents standard HTML attributes, such as class="myclass"
2
+ class HTMLAttributes
3
+ attr_reader :content
4
+ def initialize(new = nil)
5
+ @content = {}
6
+ self << new
7
+ end
8
+
9
+ def to_s
10
+ return_string = ''
11
+ @content.each_pair do |k, v|
12
+ return_string << "#{k}=\"#{v.join ' '}\" "
13
+ end
14
+
15
+ return_string.strip
16
+ end
17
+
18
+ # This is the only way we add new attributes. Flexible about what you give
19
+ # it-- accepts both strings and symbols for the keys, and both strings and
20
+ # arrays for the values.
21
+ def <<(new)
22
+ # Don't break everything if this is passed an empty value:
23
+ return self unless new
24
+
25
+ if new.is_a? Hash
26
+ add_hash(new)
27
+ else
28
+ add_string(new)
29
+ end
30
+
31
+ self
32
+ end
33
+
34
+ def delete(trash)
35
+ # accepts an array or a single element
36
+ [trash].flatten
37
+ .map(&:to_sym)
38
+ .each { |k| @content.delete k }
39
+
40
+ self
41
+ end
42
+
43
+ def replace(new)
44
+ formatted_new = if new.is_a? String
45
+ hashify_input(new)
46
+ else
47
+ new.transform_keys(&:to_sym)
48
+ end
49
+
50
+ delete formatted_new.keys
51
+
52
+ add_hash formatted_new
53
+
54
+ self
55
+ end
56
+
57
+ def empty?
58
+ @content.empty?
59
+ end
60
+
61
+ def method_missing(method, arg = nil)
62
+ if method[-1] == '='
63
+ raise 'must supply new value' unless arg
64
+
65
+ replace(method[0..-2] => arg)
66
+ elsif @content.key? method
67
+ @content[method].join(' ')
68
+ else
69
+ super
70
+ end
71
+ end
72
+
73
+ def respond_to_missing?(method, include_private = false)
74
+ (method[-1] == '=') ||
75
+ (@content.key? method) ||
76
+ super
77
+ end
78
+
79
+ private
80
+
81
+ def add_string(new_string)
82
+ add_hash hashify_input new_string
83
+ end
84
+
85
+ def add_hash(new)
86
+ formatted_new = {}
87
+ new.each_pair do |k, v|
88
+ v = v.split ' ' if v.is_a? String
89
+ formatted_new[k.to_sym] = v
90
+ end
91
+
92
+ @content.merge! formatted_new do |_key, oldval, newval|
93
+ oldval.concat newval
94
+ end
95
+ self
96
+ end
97
+
98
+ def hashify_input(new_string)
99
+ # looking for something like:
100
+ # 'class="something something-else" id="my-id"'
101
+ new_hash = {}
102
+ new_string.scan(/ ?([^="]+)="([^"]+)"/).each do |m|
103
+ # [['class','something something-else'],['id','my-id']]
104
+ new_hash[m.shift] = m.pop
105
+ end
106
+ new_hash
107
+ end
108
+ end
@@ -1,8 +1,8 @@
1
1
  # Collection of HTML element tags
2
2
  # Describes a basic, self-closing HTML tag.
3
3
  class SingleTag
4
- attr_reader :attributes
5
4
  attr_accessor :element
5
+ attr_reader :attributes
6
6
 
7
7
  # element is a string, such as 'div' or 'p'.
8
8
 
@@ -11,68 +11,16 @@ class SingleTag
11
11
 
12
12
  def initialize(element, attributes: nil)
13
13
  @element = element
14
- reset_attributes(attributes)
15
- end
16
-
17
- # Deletes all current attributes, overwrites them with supplied hash.
18
- def reset_attributes(new = nil)
19
- @attributes = {}
20
- add_attributes(new) if new
21
-
22
- self
14
+ self.attributes = attributes
23
15
  end
24
16
 
25
- # This is the only way we add new attributes. Flexible about what you give
26
- # it-- accepts both strings and symbols for the keys, and both strings and
27
- # arrays for the values.
28
-
29
- def add_attributes(new)
30
- # Don't break everything if this is passed an empty value:
31
- return self unless new
32
-
33
- if new.is_a? String
34
- add_string_attributes(new)
35
- else
36
- add_hash_attributes(new)
37
- end
38
-
39
- self
40
- end
41
- alias add_attribute add_attributes
42
-
43
- def delete_attributes(keys)
44
- # accepts an array or a single element
45
- to_delete = if keys.is_a? Array
46
- keys.map(&:to_sym)
47
- else
48
- [keys.to_sym]
49
- end
50
-
51
- to_delete.each { |k| @attributes.delete k }
52
-
53
- self
54
- end
55
- alias delete_attribute delete_attributes
56
-
57
- def rewrite_attribute(new)
58
- formatted_new = if new.is_a? String
59
- hashify_attributes(new)
60
- else
61
- new.transform_keys(&:to_sym)
62
- end
63
-
64
- delete_attributes formatted_new.keys
65
-
66
- add_hash_attributes formatted_new
17
+ def attributes=(new)
18
+ @attributes = HTMLAttributes.new(new)
67
19
  end
68
20
 
69
- # Turns attributes into a string we can insert.
70
- def render_attributes
71
- attribute_string = ''
72
- @attributes.each_pair do |k, v|
73
- attribute_string << "#{k}=\"#{v.join ' '}\" "
74
- end
75
- attribute_string.strip
21
+ # Deletes all current attributes, overwrites them with supplied hash.
22
+ def reset_attributes
23
+ @attributes = HTMLAttributes.new
76
24
  end
77
25
 
78
26
  # Returns parent, with self added as a child
@@ -80,12 +28,6 @@ class SingleTag
80
28
  parent.add_content(self)
81
29
  end
82
30
 
83
- def opening_tag
84
- output = '<' + @element
85
- output << ' ' + render_attributes unless @attributes.empty?
86
- output << '>'
87
- end
88
-
89
31
  def to_a
90
32
  [opening_tag]
91
33
  end
@@ -95,33 +37,24 @@ class SingleTag
95
37
  opening_tag + "\n"
96
38
  end
97
39
 
98
- private
99
-
100
- def add_string_attributes(new_string)
101
- add_hash_attributes hashify_attributes new_string
40
+ # Allows us to work with attributes as methods:
41
+ def method_missing(method, arg = nil)
42
+ if @attributes.respond_to?(method)
43
+ @attributes.send(method, arg)
44
+ else
45
+ super
46
+ end
102
47
  end
103
48
 
104
- def hashify_attributes(new_string)
105
- # looking for something like:
106
- # 'class="something something-else" id="my-id"'
107
- new_hash = {}
108
- new_string.scan(/ ?([^="]+)="([^"]+)"/).each do |m|
109
- # [['class','something something-else'],['id','my-id']]
110
- new_hash[m.shift] = m.pop
111
- end
112
- new_hash
49
+ def respond_to_missing?(method, include_private = false)
50
+ @attributes.respond_to?(method) || super
113
51
  end
114
52
 
115
- def add_hash_attributes(new)
116
- formatted_new = {}
117
- new.each_pair do |k, v|
118
- v = v.split ' ' if v.is_a? String
119
- formatted_new[k.to_sym] = v
120
- end
53
+ private
121
54
 
122
- @attributes.merge! formatted_new do |_key, oldval, newval|
123
- oldval.concat newval
124
- end
125
- self
55
+ def opening_tag
56
+ output = '<' + @element
57
+ output << ' ' + @attributes.to_s unless @attributes.empty?
58
+ output << '>'
126
59
  end
127
60
  end
@@ -1,3 +1,3 @@
1
1
  module ObjectiveElements
2
- VERSION = '0.4.0'.freeze
2
+ VERSION = '1.0.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: objective_elements
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Buchberger
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-10-17 00:00:00.000000000 Z
11
+ date: 2018-10-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -83,6 +83,7 @@ files:
83
83
  - bin/setup
84
84
  - lib/objective_elements.rb
85
85
  - lib/objective_elements/double_tag.rb
86
+ - lib/objective_elements/html_attributes.rb
86
87
  - lib/objective_elements/single_tag.rb
87
88
  - lib/objective_elements/version.rb
88
89
  - objective_elements.gemspec