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