talius 0.5
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 +7 -0
- data/README.md +177 -0
- data/lib/talius.rb +736 -0
- metadata +59 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: c923ee36c973d0f95514ccd29ed7d6b5181e55614c376817ff2c7cdbe4ac8291
|
4
|
+
data.tar.gz: 82037c3e6161cec2b6b7999542c0a112b1ac6de9f2329833de9dbdd3323da6d6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ea1038d7afd52feff046aab805f225cc72cc05f1a17912b483986ce29c80fb2bab171953837783827ecc32efe890af9d723278100996b2f65f4185f809ceaac2
|
7
|
+
data.tar.gz: ec31c961daf6e5d2f80e456b903fadf2130749fd672e34cf41594fac16c3664b4f28749331d3c2e3917ca9ada5ad86877a8e6565e98831e48838946313398d1c
|
data/README.md
ADDED
@@ -0,0 +1,177 @@
|
|
1
|
+
# Talius
|
2
|
+
|
3
|
+
Talius is a parser for CSS selectors. It does not parse CSS, just CSS
|
4
|
+
selectors.
|
5
|
+
|
6
|
+
`Talius.new` accepts a single string as the selector. The `Talius`
|
7
|
+
object provides an interface with which to access the properties of that
|
8
|
+
selector.
|
9
|
+
|
10
|
+
In this example, the selector consists of just `a`, meaning it selects
|
11
|
+
`<a>` tags:
|
12
|
+
|
13
|
+
<table>
|
14
|
+
<tr>
|
15
|
+
<td class='right'>
|
16
|
+
<pre>1
|
17
|
+
2
|
18
|
+
3
|
19
|
+
4
|
20
|
+
</pre>
|
21
|
+
</td>
|
22
|
+
<td>
|
23
|
+
<pre>
|
24
|
+
raw = 'a'
|
25
|
+
selector = Talius.new(raw)
|
26
|
+
rule = selector.rules[0]
|
27
|
+
rule.tags # => {"a"=>{"name"=>"a"}}
|
28
|
+
</pre>
|
29
|
+
</td>
|
30
|
+
</tr>
|
31
|
+
</table>
|
32
|
+
|
33
|
+
Line 1 creates the raw CSS selector like you might find in a CSS file. Line 2
|
34
|
+
creates a `Talius` object.
|
35
|
+
|
36
|
+
Each Talius has one or more rules. In this example the object will have one
|
37
|
+
rule. Line 3 gets that rule. Each rule has a hash of tag names in the `tags`
|
38
|
+
property. Line 4 displays that hash. See below for more about the `tags` hash.
|
39
|
+
|
40
|
+
The following sections will describe how Talius provides information about
|
41
|
+
different elements of a selector. Talius is in its infancy, so there are
|
42
|
+
some important aspects of CSS selectors that it doesn't support. Those aspects
|
43
|
+
are detailed below.
|
44
|
+
|
45
|
+
## Tags
|
46
|
+
|
47
|
+
If a selector contains a tag name, that information will be put into the
|
48
|
+
`tags` hash of the rule. Consider this example.
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
raw = 'a'
|
52
|
+
selector = Talius.new(raw)
|
53
|
+
rule = selector.rules[0]
|
54
|
+
rule.tags # => {"a"=>{"name"=>"a"}}
|
55
|
+
rule.tags['a'].class # => Talius::Node::Tag
|
56
|
+
rule.tags['a'].name # => "a"
|
57
|
+
rule.tags['a'].namespace # => nil
|
58
|
+
```
|
59
|
+
|
60
|
+
That selector consists of just a single tag name, so the `selector` object has
|
61
|
+
just one rule. That rule has a property called `tags`, which is a hash of the
|
62
|
+
tags in the rule. The key for each hash element is the name of the tag. The
|
63
|
+
value of the element is a `Talius::Node::Tag` object. That object has two
|
64
|
+
properties, `name` and `namespace`.
|
65
|
+
|
66
|
+
To indicate the namespace for the tag, put the namespace, followed by `|`,
|
67
|
+
followed by the name of the tag. For example, the following code has a selector
|
68
|
+
for tags in the `mml` namespace with the name `a`. The keys in the `tags` hash
|
69
|
+
are formatted in the same way.
|
70
|
+
|
71
|
+
```ruby
|
72
|
+
raw = 'mml|a'
|
73
|
+
selector = Talius.new(raw)
|
74
|
+
rule = selector.rules[0]
|
75
|
+
rule.tags # => {"mml|a"=>{"name"=>"a", "namespace"=>"mml"}}
|
76
|
+
rule.tags['mml|a'].class # => Talius::Node::Tag
|
77
|
+
rule.tags['mml|a'].name # => "a"
|
78
|
+
rule.tags['mml|a'].namespace # => "mml"
|
79
|
+
```
|
80
|
+
|
81
|
+
## Multiple rules
|
82
|
+
|
83
|
+
For multiple rules for a selector, separate the rules with a comma. For example,
|
84
|
+
the following code parses a selector with two rules, one for the `section` tag
|
85
|
+
and one for the `div` tag.
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
raw = 'section, div'
|
89
|
+
selector = Talius.new(raw)
|
90
|
+
selector.rules.length # => 2
|
91
|
+
selector.rules # => [{"tags"=>{"section"=>{"name"=>"section"}}}, {"tags"=>{"div"=>{"name"=>"div"}}}]
|
92
|
+
```
|
93
|
+
|
94
|
+
## IDs
|
95
|
+
|
96
|
+
If any ID descriptions are given, those IDs can be found in the rule's `ids`
|
97
|
+
hash. The keys are the names of the IDs, the values are always `true`.
|
98
|
+
|
99
|
+
```ruby
|
100
|
+
raw = '#overview'
|
101
|
+
selector = Talius.new(raw)
|
102
|
+
rule = selector.rules[0]
|
103
|
+
rule.ids # => {"overview"=>true}
|
104
|
+
```
|
105
|
+
|
106
|
+
## Classes
|
107
|
+
|
108
|
+
Classes are available in the `classes` property of the rule. `classes` is a
|
109
|
+
simple hash in which the value of each class is true.
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
raw = 'section.overview.current'
|
113
|
+
selector = Talius.new(raw)
|
114
|
+
rule = selector.rules[0]
|
115
|
+
rule.classes # => {"overview"=>true, "current"=>true}
|
116
|
+
```
|
117
|
+
|
118
|
+
## Attributes
|
119
|
+
|
120
|
+
Attribute rules are provided in the rule's `atts` hash. The hash consists of the
|
121
|
+
key of each attribute and a `Talius::Node::Att` object.
|
122
|
+
|
123
|
+
In this simple example, the selector looks for tags with an `rel` attribute.
|
124
|
+
|
125
|
+
```ruby
|
126
|
+
raw = '[rel]'
|
127
|
+
selector = Talius.new(raw)
|
128
|
+
rule = selector.rules[0]
|
129
|
+
att = rule.atts['rel']
|
130
|
+
att.class # => Talius::Node::Att
|
131
|
+
att.name # => rel
|
132
|
+
```
|
133
|
+
|
134
|
+
If you assign a value to the attribute, that value will be in `value` property.
|
135
|
+
|
136
|
+
```ruby
|
137
|
+
raw = '[rel=license]'
|
138
|
+
selector = Talius.new(raw)
|
139
|
+
rule = selector.rules[0]
|
140
|
+
att = rule.atts['rel']
|
141
|
+
att.name # => href
|
142
|
+
att.value # => license
|
143
|
+
```
|
144
|
+
|
145
|
+
Attribute namespaces are indicated in the same way as with tags. You can access
|
146
|
+
the namespace with the `namespace` property.
|
147
|
+
|
148
|
+
```ruby
|
149
|
+
raw = '[mml|rel]'
|
150
|
+
selector = Talius.new(raw)
|
151
|
+
rule = selector.rules[0]
|
152
|
+
att = rule.atts['mml|rel']
|
153
|
+
att.name # => rel
|
154
|
+
att.namespace # => mml
|
155
|
+
```
|
156
|
+
|
157
|
+
## Install
|
158
|
+
|
159
|
+
``
|
160
|
+
gem install talius
|
161
|
+
``
|
162
|
+
|
163
|
+
## Author
|
164
|
+
|
165
|
+
Mike O'Sullivan
|
166
|
+
mike@idocs.com
|
167
|
+
|
168
|
+
## Name
|
169
|
+
|
170
|
+
"Talius" doesn't mean anything in particular. It just sounded like a good name
|
171
|
+
and it was available on rubygems.rb.
|
172
|
+
|
173
|
+
## History
|
174
|
+
|
175
|
+
| version | date | notes |
|
176
|
+
|---------|--------------|-------------------------------|
|
177
|
+
| 0.5 | May 29, 2020 | Initial upload. |
|
data/lib/talius.rb
ADDED
@@ -0,0 +1,736 @@
|
|
1
|
+
require 'lx'
|
2
|
+
|
3
|
+
#===============================================================================
|
4
|
+
# Talius
|
5
|
+
#
|
6
|
+
|
7
|
+
# A +Talius+ object represents a full CSS selector.
|
8
|
+
class Talius
|
9
|
+
# version '0.5'
|
10
|
+
VERSION = '0.5'
|
11
|
+
|
12
|
+
|
13
|
+
# An array of rule objects.
|
14
|
+
attr_reader :rules
|
15
|
+
|
16
|
+
#---------------------------------------------------------------------------
|
17
|
+
# initialize
|
18
|
+
#
|
19
|
+
|
20
|
+
# Initialize a new Talius object. Takes a raw CSS selector string as the
|
21
|
+
# single param.
|
22
|
+
#
|
23
|
+
# raw = 'a[href]'
|
24
|
+
# selector = Talius.new(raw)
|
25
|
+
def initialize(p_raw)
|
26
|
+
@raw = p_raw
|
27
|
+
@rules = []
|
28
|
+
@slashes = {}
|
29
|
+
@quotes = {}
|
30
|
+
@norm = nil
|
31
|
+
|
32
|
+
# normalize selector string
|
33
|
+
unslash()
|
34
|
+
unquote()
|
35
|
+
@norm.lx.collapse!
|
36
|
+
|
37
|
+
# split into rules
|
38
|
+
@norm.split(/\s*,\s*/mu).each do |rule_str|
|
39
|
+
@rules.push Talius::Rule.new(self, rule_str)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
#
|
43
|
+
# initialize
|
44
|
+
#---------------------------------------------------------------------------
|
45
|
+
|
46
|
+
|
47
|
+
#---------------------------------------------------------------------------
|
48
|
+
# raw
|
49
|
+
#
|
50
|
+
|
51
|
+
# The original string used to the create the selector object.
|
52
|
+
#
|
53
|
+
# raw = 'a[href]'
|
54
|
+
# selector = Talius.new(raw)
|
55
|
+
# selector.raw # => "a[href]"
|
56
|
+
attr_reader :raw
|
57
|
+
|
58
|
+
#
|
59
|
+
# raw
|
60
|
+
#---------------------------------------------------------------------------
|
61
|
+
|
62
|
+
|
63
|
+
#---------------------------------------------------------------------------
|
64
|
+
# denormalize
|
65
|
+
#
|
66
|
+
|
67
|
+
# Used by Talius::Rule to rebuild a string that has placeholders in it. This
|
68
|
+
# method is not useful for any purpose beyond that.
|
69
|
+
def denormalize(raw)
|
70
|
+
return reslash(requote(raw))
|
71
|
+
end
|
72
|
+
#
|
73
|
+
# denormalize
|
74
|
+
#---------------------------------------------------------------------------
|
75
|
+
|
76
|
+
|
77
|
+
# private
|
78
|
+
private
|
79
|
+
|
80
|
+
|
81
|
+
#---------------------------------------------------------------------------
|
82
|
+
# requote
|
83
|
+
#
|
84
|
+
def requote(raw)
|
85
|
+
return @quotes[raw] || raw
|
86
|
+
end
|
87
|
+
#
|
88
|
+
# requote
|
89
|
+
#---------------------------------------------------------------------------
|
90
|
+
|
91
|
+
|
92
|
+
#---------------------------------------------------------------------------
|
93
|
+
# reslash
|
94
|
+
#
|
95
|
+
def reslash(rv)
|
96
|
+
# $tm.hrm
|
97
|
+
|
98
|
+
# loop through slashed strings
|
99
|
+
@slashes.each do |pattern, val|
|
100
|
+
rv = rv.sub(/#{pattern}/mu, val)
|
101
|
+
end
|
102
|
+
|
103
|
+
# return
|
104
|
+
return rv
|
105
|
+
end
|
106
|
+
#
|
107
|
+
# reslash
|
108
|
+
#---------------------------------------------------------------------------
|
109
|
+
|
110
|
+
|
111
|
+
#---------------------------------------------------------------------------
|
112
|
+
# unquote
|
113
|
+
#
|
114
|
+
def unquote()
|
115
|
+
rv = []
|
116
|
+
|
117
|
+
# split into slashed and unslashed strings
|
118
|
+
@norm.split(/("[^"]*")/mu).each do |token|
|
119
|
+
if token.match(/\A".*"\z/mu)
|
120
|
+
content = token
|
121
|
+
content = content.sub(/\A"/mu, '')
|
122
|
+
content = content.sub(/"\z/mu, '')
|
123
|
+
ph = LX.randstr()
|
124
|
+
@quotes[ph] = content
|
125
|
+
rv.push ph
|
126
|
+
else
|
127
|
+
rv.push token
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# return new string
|
132
|
+
@norm = rv.join('')
|
133
|
+
end
|
134
|
+
#
|
135
|
+
# unquote
|
136
|
+
#---------------------------------------------------------------------------
|
137
|
+
|
138
|
+
|
139
|
+
#---------------------------------------------------------------------------
|
140
|
+
# unslash
|
141
|
+
#
|
142
|
+
def unslash()
|
143
|
+
rv = []
|
144
|
+
|
145
|
+
# split into slashed and unslashed strings
|
146
|
+
@raw.split(/(\\.)/mu).each do |token|
|
147
|
+
if token.match(/\A\\.\z/mu)
|
148
|
+
ph = LX.randstr()
|
149
|
+
@slashes[ph] = token[1]
|
150
|
+
rv.push ph
|
151
|
+
else
|
152
|
+
rv.push token
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# return new string
|
157
|
+
@norm = rv.join('')
|
158
|
+
end
|
159
|
+
#
|
160
|
+
# unslash
|
161
|
+
#---------------------------------------------------------------------------
|
162
|
+
end
|
163
|
+
#
|
164
|
+
# Talius
|
165
|
+
#===============================================================================
|
166
|
+
|
167
|
+
|
168
|
+
#===============================================================================
|
169
|
+
# Talius::Rule
|
170
|
+
#
|
171
|
+
|
172
|
+
# Talius::Rule object represents one set of directives, e.g. tags, classes, etc.
|
173
|
+
class Talius::Rule
|
174
|
+
#---------------------------------------------------------------------------
|
175
|
+
# special characters
|
176
|
+
#
|
177
|
+
@@NESTING_CHARS = %w{> + ~ s}
|
178
|
+
@@NESTING_RX = @@NESTING_CHARS.map{|el| '\\' + el}.join('')
|
179
|
+
@@SUBRULE_CHARS = %w{. [ ] : #}
|
180
|
+
@@SUBRULE_RX = @@SUBRULE_CHARS.map{|el| '\\' + el}.join('')
|
181
|
+
@@META_RX = @@NESTING_RX + @@SUBRULE_RX
|
182
|
+
#
|
183
|
+
# special characters
|
184
|
+
#---------------------------------------------------------------------------
|
185
|
+
|
186
|
+
|
187
|
+
#---------------------------------------------------------------------------
|
188
|
+
# initialize
|
189
|
+
# Lexical parsing experts will probably recoil in horror at how I parse a
|
190
|
+
# selector rule. Whatever.
|
191
|
+
#
|
192
|
+
|
193
|
+
# Initializes a Talius::Rule object. The first param is the Talius object
|
194
|
+
# with which the rule will be associated. The second param is the raw string
|
195
|
+
# that describes the rule.
|
196
|
+
#
|
197
|
+
# raw = 'section, div'
|
198
|
+
# selector = Talius.new(raw)
|
199
|
+
# selector.rules[0] # => {"tags"=>{"section"=>{"name"=>"section"}}}
|
200
|
+
def initialize(p_selector, raw)
|
201
|
+
@selector = p_selector
|
202
|
+
@classes = {}
|
203
|
+
@tags = {}
|
204
|
+
@ids = {}
|
205
|
+
@pelements = {}
|
206
|
+
@pclasses = {}
|
207
|
+
@atts = {}
|
208
|
+
|
209
|
+
# remove spaces before and after parens
|
210
|
+
raw = raw.gsub(/\s*([\(\)])\s*/mu, '\1')
|
211
|
+
|
212
|
+
# split into subrules
|
213
|
+
pieces = raw.split(/(\[[^\[\]]*\])|(\:\:[^#{@@META_RX}]+)|([#{@@NESTING_RX}])|([#{@@META_RX}][^#{@@META_RX}]*)/mu)
|
214
|
+
pieces = pieces.grep(/./mu)
|
215
|
+
|
216
|
+
# build subrules
|
217
|
+
pieces.each do |piece|
|
218
|
+
# I haven't yet implemented nested rules, so at this point we should
|
219
|
+
# not have any pieces that consist of just spaces
|
220
|
+
if @@NESTING_CHARS.include?(piece)
|
221
|
+
raise 'not-yet-implemented-nested-elements: ' + piece
|
222
|
+
end
|
223
|
+
|
224
|
+
# if piece consists of a single meta character, that's invalid
|
225
|
+
if @@SUBRULE_CHARS.include?(piece)
|
226
|
+
raise 'meta-character-without-value: ' + piece
|
227
|
+
end
|
228
|
+
|
229
|
+
# class
|
230
|
+
if piece.match(/\A\..+/mu)
|
231
|
+
@classes[piece.sub(/\A\./mu, '')] = true
|
232
|
+
|
233
|
+
# pseudo element ::
|
234
|
+
elsif piece.match(/\A\:\:/mu)
|
235
|
+
pe = piece.sub(/\A\:\:/mu, '')
|
236
|
+
pseudo @pelements, pe
|
237
|
+
|
238
|
+
# pseudo class :
|
239
|
+
elsif piece.match(/\A\:/mu)
|
240
|
+
pc = piece.sub(/\A\:/mu, '')
|
241
|
+
pseudo @pclasses, pc
|
242
|
+
|
243
|
+
# attribute
|
244
|
+
elsif piece.match(/\A\[.*\]\z/mu)
|
245
|
+
full = piece
|
246
|
+
full = full.sub(/\A\s*\[\s*/mu, '')
|
247
|
+
full = full.sub(/\s*\]\s*\z/mu, '')
|
248
|
+
nv = full.split(/\s*\=\s*/mu, 2)
|
249
|
+
|
250
|
+
if nv[0]
|
251
|
+
att = Talius::Node::Att.new(@selector.denormalize(nv[0]))
|
252
|
+
@atts[att.full_name] = att
|
253
|
+
|
254
|
+
if nv[1]
|
255
|
+
att.value = @selector.denormalize(nv[1])
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
# id
|
260
|
+
elsif piece.match(/\A\#/mu)
|
261
|
+
id = piece
|
262
|
+
id = id.sub(/\A\#/mu, '')
|
263
|
+
@ids[id] = true
|
264
|
+
|
265
|
+
# else tag
|
266
|
+
else
|
267
|
+
tag = Talius::Node::Tag.new(@selector.denormalize(piece))
|
268
|
+
@tags[tag.full_name] = tag
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
#
|
273
|
+
# initialize
|
274
|
+
#---------------------------------------------------------------------------
|
275
|
+
|
276
|
+
|
277
|
+
#---------------------------------------------------------------------------
|
278
|
+
# selector
|
279
|
+
#
|
280
|
+
|
281
|
+
# The +Talius+ object that this rule is associated with.
|
282
|
+
attr_reader :selector
|
283
|
+
|
284
|
+
#
|
285
|
+
# selector
|
286
|
+
#---------------------------------------------------------------------------
|
287
|
+
|
288
|
+
|
289
|
+
#---------------------------------------------------------------------------
|
290
|
+
# classes
|
291
|
+
#
|
292
|
+
|
293
|
+
# A hash of the classes described in the selector. The hash keys are the
|
294
|
+
# names of the classes. The values are always true.
|
295
|
+
#
|
296
|
+
# raw = 'section.ready.overview'
|
297
|
+
# selector = Talius.new(raw)
|
298
|
+
# selector.rules[0].classes # => {"ready"=>true, "overview"=>true}
|
299
|
+
attr_reader :classes
|
300
|
+
|
301
|
+
#
|
302
|
+
# classes
|
303
|
+
#---------------------------------------------------------------------------
|
304
|
+
|
305
|
+
|
306
|
+
#---------------------------------------------------------------------------
|
307
|
+
# tags
|
308
|
+
#
|
309
|
+
|
310
|
+
# A hash of the tags described in the selector. The hash keys are the names
|
311
|
+
# if the tags. The values are Talius::Node::Tag objects. Currently, Talius
|
312
|
+
# can only parse a single tag from a selector rule, so for now this hash
|
313
|
+
# will always have a single element.
|
314
|
+
#
|
315
|
+
# raw = 'section'
|
316
|
+
# selector = Talius.new(raw)
|
317
|
+
# selector.rules[0].tags # => {"section"=>{"name"=>"section"}}
|
318
|
+
attr_reader :tags
|
319
|
+
|
320
|
+
#
|
321
|
+
# tags
|
322
|
+
#---------------------------------------------------------------------------
|
323
|
+
|
324
|
+
|
325
|
+
#---------------------------------------------------------------------------
|
326
|
+
# ids
|
327
|
+
#
|
328
|
+
|
329
|
+
# A hash of elements defined by ID. The hash keys are the id's, the
|
330
|
+
# values are always true
|
331
|
+
#
|
332
|
+
# raw = '#overview'
|
333
|
+
# selector = Talius.new(raw)
|
334
|
+
# rule = selector.rules[0]
|
335
|
+
# rule.ids # => {"overview"=>true}
|
336
|
+
|
337
|
+
attr_reader :ids
|
338
|
+
|
339
|
+
#
|
340
|
+
# ids
|
341
|
+
#---------------------------------------------------------------------------
|
342
|
+
|
343
|
+
|
344
|
+
#---------------------------------------------------------------------------
|
345
|
+
# pelements
|
346
|
+
#
|
347
|
+
|
348
|
+
# A hash of pseudo-elements such as +::first-line+. The hash keys are the
|
349
|
+
# names of the pseudo-elements. The values are either the value in the
|
350
|
+
# parens after the name of the pseudo-element, or, if there is no such
|
351
|
+
# value, +nil+.
|
352
|
+
#
|
353
|
+
# raw = 'section::first-line'
|
354
|
+
# selector = Talius.new(raw)
|
355
|
+
# selector.rules[0].pelements # => {"first-line"=>nil}
|
356
|
+
#
|
357
|
+
# raw = 'section::nth-line(9)'
|
358
|
+
# selector = Talius.new(raw)
|
359
|
+
# selector.rules[0].pelements # => {"nth-line"=>"9"}
|
360
|
+
|
361
|
+
attr_reader :pelements
|
362
|
+
|
363
|
+
#
|
364
|
+
# pelements
|
365
|
+
#---------------------------------------------------------------------------
|
366
|
+
|
367
|
+
|
368
|
+
#---------------------------------------------------------------------------
|
369
|
+
# pclasses
|
370
|
+
#
|
371
|
+
|
372
|
+
# A hash of pseudo-classes such as +:visited+. The hash keys are the
|
373
|
+
# names of the pseudo-elements. The values are either the value in the
|
374
|
+
# parens after the name of the pseudo-element, or, if there is no such
|
375
|
+
# value, +nil+.
|
376
|
+
#
|
377
|
+
# raw = 'a:visited'
|
378
|
+
# selector = Talius.new(raw)
|
379
|
+
# selector.rules[0].pclasses # => {"visited"=>nil}
|
380
|
+
#
|
381
|
+
# raw = 'ul:nth-child(9)'
|
382
|
+
# selector = Talius.new(raw)
|
383
|
+
# selector.rules[0].pclasses # => {"nth-child"=>"9"}
|
384
|
+
|
385
|
+
attr_reader :pclasses
|
386
|
+
|
387
|
+
#
|
388
|
+
# pclasses
|
389
|
+
#---------------------------------------------------------------------------
|
390
|
+
|
391
|
+
|
392
|
+
#---------------------------------------------------------------------------
|
393
|
+
# atts
|
394
|
+
#
|
395
|
+
|
396
|
+
# Hash of attributes. The hash keys are the names of the attributes. The
|
397
|
+
# values are Talius::Node::Att objects.
|
398
|
+
#
|
399
|
+
# raw = 'a[href][rel=parent]'
|
400
|
+
# selector = Talius.new(raw)
|
401
|
+
# selector.rules[0].atts # => {"href"=>{"name"=>"href"}, "rel"=>{"name"=>"rel", "value"=>"parent"}}
|
402
|
+
|
403
|
+
attr_reader :atts
|
404
|
+
|
405
|
+
#
|
406
|
+
# atts
|
407
|
+
#---------------------------------------------------------------------------
|
408
|
+
|
409
|
+
|
410
|
+
#---------------------------------------------------------------------------
|
411
|
+
# to_h
|
412
|
+
#
|
413
|
+
|
414
|
+
# Returns a hash representation of the rule.
|
415
|
+
def to_h
|
416
|
+
# $tm.hrm
|
417
|
+
rv = {}
|
418
|
+
|
419
|
+
# tags
|
420
|
+
if @tags.any?
|
421
|
+
rv['tags'] = {}.tap do |tags|
|
422
|
+
@tags.each do |key, node|
|
423
|
+
tags[node.full_name] = node.to_h
|
424
|
+
end
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
428
|
+
# ids
|
429
|
+
if @ids.any?
|
430
|
+
rv['ids'] = {}.tap do |ids|
|
431
|
+
@ids.each do |key, val|
|
432
|
+
ids[key] = val
|
433
|
+
end
|
434
|
+
end
|
435
|
+
end
|
436
|
+
|
437
|
+
# atts
|
438
|
+
if @atts.any?
|
439
|
+
rv['atts'] = {}.tap do |atts|
|
440
|
+
@atts.each do |key, node|
|
441
|
+
atts[node.full_name] = node.to_h
|
442
|
+
end
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
446
|
+
# classes
|
447
|
+
if @classes.any?
|
448
|
+
rv['classes'] = {}.tap do |classes|
|
449
|
+
@classes.each do |key, val|
|
450
|
+
classes[key] = val
|
451
|
+
end
|
452
|
+
end
|
453
|
+
end
|
454
|
+
|
455
|
+
# pclasses
|
456
|
+
if @pclasses.any?
|
457
|
+
rv['pclasses'] = {}.tap do |pclasses|
|
458
|
+
@pclasses.each do |key, val|
|
459
|
+
pclasses[key] = val
|
460
|
+
end
|
461
|
+
end
|
462
|
+
end
|
463
|
+
|
464
|
+
# pelements
|
465
|
+
if @pelements.any?
|
466
|
+
rv['pelements'] = {}.tap do |pelements|
|
467
|
+
@pelements.each do |key, val|
|
468
|
+
pelements[key] = val
|
469
|
+
end
|
470
|
+
end
|
471
|
+
end
|
472
|
+
|
473
|
+
# return
|
474
|
+
return rv
|
475
|
+
end
|
476
|
+
#
|
477
|
+
# to_h
|
478
|
+
#---------------------------------------------------------------------------
|
479
|
+
|
480
|
+
|
481
|
+
#---------------------------------------------------------------------------
|
482
|
+
# inspect
|
483
|
+
#
|
484
|
+
|
485
|
+
# Returns a stringification of the results of to_h.
|
486
|
+
def inspect
|
487
|
+
return to_h.to_s
|
488
|
+
end
|
489
|
+
#
|
490
|
+
# inspect
|
491
|
+
#---------------------------------------------------------------------------
|
492
|
+
|
493
|
+
|
494
|
+
# private
|
495
|
+
private
|
496
|
+
|
497
|
+
|
498
|
+
#---------------------------------------------------------------------------
|
499
|
+
# pseudo
|
500
|
+
#
|
501
|
+
def pseudo(hsh, raw)
|
502
|
+
# get value in parens
|
503
|
+
if raw.match(/\(/mu)
|
504
|
+
val = raw
|
505
|
+
raw = raw.sub(/\(.*/mu, '')
|
506
|
+
val = val.sub(/\A.*\(/mu, '')
|
507
|
+
val = val.sub(/\)\z/mu, '')
|
508
|
+
hsh[@selector.denormalize(raw).downcase] = @selector.denormalize(val)
|
509
|
+
else
|
510
|
+
hsh[@selector.denormalize(raw).downcase] = nil
|
511
|
+
end
|
512
|
+
end
|
513
|
+
#
|
514
|
+
# pseudo
|
515
|
+
#---------------------------------------------------------------------------
|
516
|
+
end
|
517
|
+
#
|
518
|
+
# Talius::Rule
|
519
|
+
#===============================================================================
|
520
|
+
|
521
|
+
|
522
|
+
#===============================================================================
|
523
|
+
# Talius::Node
|
524
|
+
#
|
525
|
+
|
526
|
+
# Base class for Talius::Node::Tag and Talius::Node::Att.
|
527
|
+
class Talius::Node
|
528
|
+
#---------------------------------------------------------------------------
|
529
|
+
# initialize
|
530
|
+
#
|
531
|
+
|
532
|
+
# Initializes a new node. Accepts the string from the selector. Generally,
|
533
|
+
# you won't have to instantiate a Talius::Node object yourself.
|
534
|
+
def initialize(raw)
|
535
|
+
tokens = raw.split('|', 2)
|
536
|
+
|
537
|
+
# if one element
|
538
|
+
if tokens.length == 1
|
539
|
+
@namespace = nil
|
540
|
+
@name = tokens[0]
|
541
|
+
elsif tokens.length == 2
|
542
|
+
@namespace = tokens[0]
|
543
|
+
@name = tokens[1]
|
544
|
+
else
|
545
|
+
raise 'node-syntax-error: ' + raw.to_s
|
546
|
+
end
|
547
|
+
end
|
548
|
+
#
|
549
|
+
# initialize
|
550
|
+
#---------------------------------------------------------------------------
|
551
|
+
|
552
|
+
|
553
|
+
#---------------------------------------------------------------------------
|
554
|
+
# The node's namespace. If a namespace is not explicitly given in the
|
555
|
+
# selector string then this property is nil.
|
556
|
+
#
|
557
|
+
# raw = 'section, mml|dev'
|
558
|
+
# selector = Talius.new(raw)
|
559
|
+
# selector.rules[0].tags['section'].namespace # => nil
|
560
|
+
# selector.rules[1].tags['mml|dev'].namespace # => "mml"
|
561
|
+
attr_reader :namespace
|
562
|
+
#
|
563
|
+
# namespace
|
564
|
+
#---------------------------------------------------------------------------
|
565
|
+
|
566
|
+
|
567
|
+
#---------------------------------------------------------------------------
|
568
|
+
# name
|
569
|
+
#
|
570
|
+
|
571
|
+
# The name of the tag or attribute. Does not include the namespace.
|
572
|
+
#
|
573
|
+
# raw = 'section, mml|dev'
|
574
|
+
# selector = Talius.new(raw)
|
575
|
+
# selector.rules[0].tags['section'].name # => "section"
|
576
|
+
# selector.rules[1].tags['mml|dev'].name # => "dev"
|
577
|
+
attr_reader :name
|
578
|
+
#
|
579
|
+
# name
|
580
|
+
#---------------------------------------------------------------------------
|
581
|
+
|
582
|
+
|
583
|
+
#---------------------------------------------------------------------------
|
584
|
+
# full_name
|
585
|
+
#
|
586
|
+
|
587
|
+
# Returns the namespace (if there is one) and the name of the node. If there
|
588
|
+
# is a namespace then the namespace is followed by |.
|
589
|
+
#
|
590
|
+
# raw = 'section, mml|dev'
|
591
|
+
# selector = Talius.new(raw)
|
592
|
+
# selector.rules[0].tags['section'].fullname # => "section"
|
593
|
+
# selector.rules[1].tags['mml|dev'].fullname # => "mml|dev"
|
594
|
+
def full_name
|
595
|
+
if @namespace
|
596
|
+
return @namespace + '|' + @name
|
597
|
+
else
|
598
|
+
return @name
|
599
|
+
end
|
600
|
+
end
|
601
|
+
#
|
602
|
+
# full_name
|
603
|
+
#---------------------------------------------------------------------------
|
604
|
+
|
605
|
+
|
606
|
+
#---------------------------------------------------------------------------
|
607
|
+
# to_s
|
608
|
+
#
|
609
|
+
|
610
|
+
# Returns the results of +full_name+.
|
611
|
+
def to_s
|
612
|
+
return full_name
|
613
|
+
end
|
614
|
+
#
|
615
|
+
# to_s
|
616
|
+
#---------------------------------------------------------------------------
|
617
|
+
|
618
|
+
|
619
|
+
#---------------------------------------------------------------------------
|
620
|
+
# to_h
|
621
|
+
#
|
622
|
+
|
623
|
+
# Returns a hash of the name and namespace (if there is a namespace).
|
624
|
+
#
|
625
|
+
# raw = 'section, mml|dev'
|
626
|
+
# selector = Talius.new(raw)
|
627
|
+
# selector.rules[0].tags['section'].to_h # => {"name"=>"section"}
|
628
|
+
# selector.rules[1].tags['mml|dev'].to_h # => {"name"=>"dev", "namespace"=>"mml"}
|
629
|
+
def to_h
|
630
|
+
rv = {}
|
631
|
+
rv['name'] = @name
|
632
|
+
|
633
|
+
# namespace
|
634
|
+
if @namespace
|
635
|
+
rv['namespace'] = @namespace
|
636
|
+
end
|
637
|
+
|
638
|
+
return rv
|
639
|
+
end
|
640
|
+
#
|
641
|
+
# to_h
|
642
|
+
#---------------------------------------------------------------------------
|
643
|
+
|
644
|
+
|
645
|
+
#---------------------------------------------------------------------------
|
646
|
+
# inspect
|
647
|
+
#
|
648
|
+
|
649
|
+
# Returns the stringification of the hash returned by +to_h+.
|
650
|
+
# raw = 'section, mml|dev'
|
651
|
+
# selector = Talius.new(raw)
|
652
|
+
# selector.rules[0].tags['section'].inspect # => {"name"=>"section"}
|
653
|
+
# selector.rules[1].tags['mml|dev'].inspect # => {"name"=>"dev", "namespace"=>"mml"}
|
654
|
+
def inspect
|
655
|
+
return to_h.inspect
|
656
|
+
end
|
657
|
+
#
|
658
|
+
# inspect
|
659
|
+
#---------------------------------------------------------------------------
|
660
|
+
end
|
661
|
+
#
|
662
|
+
# Talius::Node
|
663
|
+
#===============================================================================
|
664
|
+
|
665
|
+
|
666
|
+
#===============================================================================
|
667
|
+
# Talius::Node::Tag
|
668
|
+
#
|
669
|
+
|
670
|
+
# This class inherits from Talius::Node and adds nothing to it.
|
671
|
+
class Talius::Node::Tag < Talius::Node
|
672
|
+
end
|
673
|
+
#
|
674
|
+
# Talius::Node::Tag
|
675
|
+
#===============================================================================
|
676
|
+
|
677
|
+
|
678
|
+
#===============================================================================
|
679
|
+
# Talius::Node::Att
|
680
|
+
#
|
681
|
+
|
682
|
+
# This class inherits from Talius::Node and adds the value property.
|
683
|
+
class Talius::Node::Att < Talius::Node
|
684
|
+
#---------------------------------------------------------------------------
|
685
|
+
# initialize
|
686
|
+
#
|
687
|
+
def initialize(*opts)
|
688
|
+
super(*opts)
|
689
|
+
@value = nil
|
690
|
+
end
|
691
|
+
#
|
692
|
+
# initialize
|
693
|
+
#---------------------------------------------------------------------------
|
694
|
+
|
695
|
+
|
696
|
+
#---------------------------------------------------------------------------
|
697
|
+
# value
|
698
|
+
#
|
699
|
+
|
700
|
+
# The value of the attribute rule, if there is one.
|
701
|
+
#
|
702
|
+
# raw = 'a[href][rel=parent]'
|
703
|
+
# selector = Talius.new(raw)
|
704
|
+
# rule = selector.rules[0]
|
705
|
+
# rule.atts['href'].value # => nil
|
706
|
+
# rule.atts['rel'].value # => "parent"
|
707
|
+
|
708
|
+
attr_accessor :value
|
709
|
+
|
710
|
+
#
|
711
|
+
# value
|
712
|
+
#---------------------------------------------------------------------------
|
713
|
+
|
714
|
+
|
715
|
+
#---------------------------------------------------------------------------
|
716
|
+
# to_h
|
717
|
+
#
|
718
|
+
|
719
|
+
# Returns a hash representation of the obect.
|
720
|
+
def to_h
|
721
|
+
rv = super()
|
722
|
+
|
723
|
+
# value
|
724
|
+
if @value
|
725
|
+
rv['value'] = @value
|
726
|
+
end
|
727
|
+
|
728
|
+
return rv
|
729
|
+
end
|
730
|
+
#
|
731
|
+
# to_h
|
732
|
+
#---------------------------------------------------------------------------
|
733
|
+
end
|
734
|
+
#
|
735
|
+
# Talius::Node::Att
|
736
|
+
#===============================================================================
|
metadata
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: talius
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0.5'
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Mike O'Sullivan
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-05-29 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: lx.rb
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.0'
|
27
|
+
description: CSS selector parser
|
28
|
+
email: mike@idocs.com
|
29
|
+
executables: []
|
30
|
+
extensions: []
|
31
|
+
extra_rdoc_files: []
|
32
|
+
files:
|
33
|
+
- README.md
|
34
|
+
- lib/talius.rb
|
35
|
+
homepage: https://rubygems.org/gems/talius
|
36
|
+
licenses:
|
37
|
+
- MIT
|
38
|
+
metadata: {}
|
39
|
+
post_install_message:
|
40
|
+
rdoc_options: []
|
41
|
+
require_paths:
|
42
|
+
- lib
|
43
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '0'
|
53
|
+
requirements: []
|
54
|
+
rubyforge_project:
|
55
|
+
rubygems_version: 2.7.6
|
56
|
+
signing_key:
|
57
|
+
specification_version: 4
|
58
|
+
summary: CSS selector parser
|
59
|
+
test_files: []
|