objective_elements 0.4.0 → 1.0.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: 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