hexp 0.2.0 → 0.3.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 +15 -0
- data/.gitignore +4 -0
- data/.travis.yml +2 -3
- data/.yardopts +1 -0
- data/Gemfile.devtools +17 -24
- data/Gemfile.lock +77 -82
- data/{LICENSE.md → LICENSE} +0 -0
- data/README.md +20 -10
- data/Rakefile +17 -1
- data/bench/node/rewrite_bench.rb +23 -0
- data/config/flay.yml +1 -1
- data/config/flog.yml +1 -1
- data/config/reek.yml +6 -0
- data/config/yardstick.yml +7 -2
- data/hexp.gemspec +6 -5
- data/lib/hexp.rb +26 -18
- data/lib/hexp/builder.rb +54 -35
- data/lib/hexp/css_selector.rb +124 -25
- data/lib/hexp/css_selector/parser.rb +45 -2
- data/lib/hexp/css_selector/sass_parser.rb +16 -0
- data/lib/hexp/dom.rb +2 -0
- data/lib/hexp/dsl.rb +20 -21
- data/lib/hexp/errors.rb +2 -2
- data/lib/hexp/list.rb +14 -11
- data/lib/hexp/node.rb +89 -38
- data/lib/hexp/node/attributes.rb +43 -26
- data/lib/hexp/node/children.rb +59 -4
- data/lib/hexp/node/css_selection.rb +113 -7
- data/lib/hexp/node/domize.rb +22 -13
- data/lib/hexp/node/normalize.rb +3 -9
- data/lib/hexp/node/pp.rb +13 -9
- data/lib/hexp/node/rewriter.rb +28 -3
- data/lib/hexp/node/{selector.rb → selection.rb} +48 -2
- data/lib/hexp/nokogiri/reader.rb +2 -2
- data/lib/hexp/text_node.rb +1 -1
- data/lib/hexp/version.rb +1 -1
- data/spec/unit/hexp/css_selector/universal_spec.rb +7 -0
- data/spec/unit/hexp/node/domize_spec.rb +12 -0
- data/spec/unit/hexp/node/{selector_spec.rb → selection_spec.rb} +9 -9
- data/spec/unit/hexp/parse_spec.rb +10 -0
- metadata +40 -44
- data/SPEC.md +0 -53
- data/notes +0 -34
data/SPEC.md
DELETED
@@ -1,53 +0,0 @@
|
|
1
|
-
# HTML Expressions (hexp) Specification
|
2
|
-
|
3
|
-
HTML Expressions, hexps for short, are a subset of s-expressions. They provide a convention for working with HTML data in applications in a structured fashion.
|
4
|
-
|
5
|
-
Most languages contain a DOM implementation to work with HTML/XML documents, fragments and nodes. However, generating HTML through the DOM API is verbose and tedious. A hexp implementation SHOULD implement conversions from and to DOM documents. A hexp implementation SHOULD NOT convert directly from or to HTML.
|
6
|
-
|
7
|
-
A hexp implementation MUST implement hexp normalization. Several shorthands are provided for the convenience of the programmer when entering literal hexps. These non-strict hexps should be normalized to strict hexps before further manipulation.
|
8
|
-
|
9
|
-
## Strict hexps
|
10
|
-
|
11
|
-
A strict hexp is a triplet, it represents a single HTML node. The first element is the tag name, the second a dictionary of attributes, the third is a list of child nodes.
|
12
|
-
|
13
|
-
If the language implements the concept of a symbol (interned string), the tag name MUST BE a symbol. Otherwise it will be represented as a regular string.
|
14
|
-
|
15
|
-
The attributes are represented in a dictionary (hash), with both keys and values being strings.
|
16
|
-
|
17
|
-
The list of child nodes is a list (array) of other hexps or strings, the latter representing text nodes in the corresponding DOM.
|
18
|
-
|
19
|
-
An example in Ruby of a strict hexp :
|
20
|
-
|
21
|
-
````ruby
|
22
|
-
[:div, {'class': 'hexp-example'}, [
|
23
|
-
[:p, {}, "Hello, world"]
|
24
|
-
]
|
25
|
-
]
|
26
|
-
````
|
27
|
-
|
28
|
-
A normalized hexp MUST be made immutable (frozen, persistent) if the runtime supports it. Operations that alter a hexp MUST return a new hexp values, rather than changing the hexp value in-place.
|
29
|
-
|
30
|
-
## Non-strict hexps
|
31
|
-
|
32
|
-
Following simplifications are allowed for entering literal hexps, the implementation MUST provide a mechanism for converting these to strict hexps.
|
33
|
-
|
34
|
-
````ruby
|
35
|
-
# non-strict -> strict
|
36
|
-
[:p] -> [:p, {}, []]
|
37
|
-
[:p, {'class' => 'foo'}] -> [:p, {'class' => 'foo'}, []]
|
38
|
-
[:p, ['hello,', [:br], 'world'] -> [:p, {}, ['hello,', [:br, {}, []], 'world']
|
39
|
-
````
|
40
|
-
|
41
|
-
### Omitting attributes or children
|
42
|
-
|
43
|
-
If the dictionary of attributes is empty, it may be omitted.
|
44
|
-
|
45
|
-
If the list of children is empty, it may be omitted.
|
46
|
-
|
47
|
-
### A single text node as child
|
48
|
-
|
49
|
-
If the represented node its only child is a text node, a single string may be given rather than a list of children. An example would be `<p>Hello, world</p>`, this can be represented as `[:p, "Hello, world"]`, which would be normalized to `[:p, {}, ["Hello, world"]]`.
|
50
|
-
|
51
|
-
### Standard coercion protocol
|
52
|
-
|
53
|
-
In a dynamically typed object-oriented language, a convention may be set for a protocol that objects can implement to return a strict hexp representation of themselves. For Ruby this will be the `to_hexp` method. In the list of children, objects can be added that implement `to_hexp`. The normalization procedure must detect that the object implements this method, and add the resulting hexps to the list of children.
|
data/notes
DELETED
@@ -1,34 +0,0 @@
|
|
1
|
-
http://begriffs.github.io/showpiece/
|
2
|
-
|
3
|
-
TODO
|
4
|
-
====
|
5
|
-
* Rename Hexp::Node to Hexp::Element
|
6
|
-
* Rename Selector to Selection
|
7
|
-
|
8
|
-
Issues
|
9
|
-
======
|
10
|
-
|
11
|
-
Root elements should not be treated separately
|
12
|
-
|
13
|
-
A `rewrite` operation currently yields all nodes except the root node. Rewrite allows you to replace a node with zero, one or more nodes. My thinking at the time was that I wanted to make sure a single Hexp was returned, so if one could rewrite the root node that would be problematic.
|
14
|
-
|
15
|
-
This however makes for a special case that is not very intuitive. When implementing `Hexp::Node::Selector` I came across this again. One can use a Selector strictly as an Enumerable
|
16
|
-
|
17
|
-
```ruby
|
18
|
-
# Find the first child element of all elements with class="strong"
|
19
|
-
hexp.select {|el| el.class? 'strong' }.map {|el| el.children.first }
|
20
|
-
```
|
21
|
-
|
22
|
-
In this case there is no reason why that shouldn't iterate the whole tree, including the node. Other operations on `Selector` however do a Rewrite of the selected elements, and in this case the "all-except-the-root-node" limitation applies.
|
23
|
-
|
24
|
-
``` ruby
|
25
|
-
# Add class="strong" to all divs
|
26
|
-
H[:div, [
|
27
|
-
[:div, 'one'],
|
28
|
-
[:div, 'two']
|
29
|
-
]
|
30
|
-
].select{|node| node.tag==:div}.attr('class', 'strong').to_hexp
|
31
|
-
#=> H[:div, [H[:div, {"class"=>"strong"}, ["one"]], H[:div, {"class"=>"strong"}, ["two"]]]]
|
32
|
-
```
|
33
|
-
|
34
|
-
The top-level node is unaffected. To remove this limitation `Rewriter` will have to return a `Hexp::List` when zero or multiple elements are returned. Hexp::Node and Hexp::List will also have to implement as much as possible the same interface, so they can be largely used intechangably. This should especially be possible for all select/rewrite operations.
|