docstache 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/changelog.md +7 -2
- data/lib/docstache/block.rb +10 -9
- data/lib/docstache/data_scope.rb +54 -6
- data/lib/docstache/document.rb +3 -3
- data/lib/docstache/renderer.rb +5 -5
- data/lib/docstache/version.rb +1 -1
- data/lib/docstache.rb +5 -5
- metadata +11 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3b400a5b0a023a3d6a9deb3835faff68ee17a5d7
|
4
|
+
data.tar.gz: 59c5ff97e4c9f34aad5c38a793bf937efcf4aa80
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2130ef05930e66377c40bae00a9dabb56c9a247c8f86de787881630b02f76bc669c59ced04108091f8ec24646dc80fb286dbab5933527a0325952bb93c9f9c68
|
7
|
+
data.tar.gz: 7bf46117d6252fe7dbbeb729a94a459ed24c8968b7746102006df2e11ff7e75f4a379a4818575878155cfbcdb2cad3bb360b81be80e55c3c79becfdb88e0d86b
|
data/changelog.md
CHANGED
@@ -1,12 +1,17 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 0.2.0
|
4
|
+
|
5
|
+
* [902d9890bee1a20a90377a94c3096a51781e8a24] You can access array elements with `[]`s within a `{{tag}}`
|
6
|
+
* [a36c4fefed763b6a54d15564e887fbcf3c3421e3] You can use conditions on loops to only loop over specific elements
|
7
|
+
|
3
8
|
## 0.1.0
|
4
9
|
|
5
|
-
* [
|
10
|
+
* [08f09d1922e73ccaf17989a568deeb2ce0ebd4b8] Hash keys inside DataScope are symbolized
|
6
11
|
|
7
12
|
## 0.0.6
|
8
13
|
|
9
|
-
* [
|
14
|
+
* [f945bc70ebb684f21e2488a3ad30c205bc05ddbb] Fixed a bug When two tags were inside one xml node, it would mistakenly report that there was an error when there wasn't.
|
10
15
|
|
11
16
|
## 0.0.5
|
12
17
|
|
data/lib/docstache/block.rb
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
module Docstache
|
2
2
|
class Block
|
3
|
-
attr_reader :name, :opening_element, :content_elements, :closing_element, :inverted
|
4
|
-
def initialize(name:, data:, opening_element:, content_elements:, closing_element:, inverted:)
|
3
|
+
attr_reader :name, :opening_element, :content_elements, :closing_element, :inverted, :condition
|
4
|
+
def initialize(name:, data:, opening_element:, content_elements:, closing_element:, inverted:, condition: nil)
|
5
5
|
@name = name
|
6
6
|
@data = data
|
7
7
|
@opening_element = opening_element
|
8
8
|
@content_elements = content_elements
|
9
9
|
@closing_element = closing_element
|
10
10
|
@inverted = inverted
|
11
|
+
@condition = condition
|
11
12
|
end
|
12
13
|
|
13
14
|
def type
|
@@ -30,14 +31,14 @@ module Docstache
|
|
30
31
|
type == :conditional
|
31
32
|
end
|
32
33
|
|
33
|
-
def self.find_all(name:, data:, elements:, inverted:)
|
34
|
-
if elements.text.match(/\{\{#{inverted ? '\^' : '\#'}#{name}\}\}
|
35
|
-
if elements.any? { |e| e.text.match(/\{\{#{inverted ? '\^' : '\#'}#{name}\}\}
|
36
|
-
matches = elements.select { |e| e.text.match(/\{\{#{inverted ? '\^' : '\#'}#{name}\}\}
|
37
|
-
finds = matches.map { |match| find_all(name: name, data: data, elements: match.elements, inverted: inverted) }.flatten
|
34
|
+
def self.find_all(name:, data:, elements:, inverted:, condition: nil)
|
35
|
+
if elements.text.match(/\{\{#{inverted ? '\^' : '\#'}#{name}#{condition ? " when #{condition}" : ''}\}\}.+?\{\{\/#{name}\}\}/m)
|
36
|
+
if elements.any? { |e| e.text.match(/\{\{#{inverted ? '\^' : '\#'}#{name}#{condition ? " when #{condition}" : ''}\}\}.+?\{\{\/#{name}\}\}/m) }
|
37
|
+
matches = elements.select { |e| e.text.match(/\{\{#{inverted ? '\^' : '\#'}#{name}#{condition ? " when #{condition}" : ''}\}\}.+?\{\{\/#{name}\}\}/m) }
|
38
|
+
finds = matches.map { |match| find_all(name: name, data: data, elements: match.elements, inverted: inverted, condition: condition) }.flatten
|
38
39
|
return finds
|
39
40
|
else
|
40
|
-
opening = elements.select { |e| e.text.match(/\{\{#{inverted ? '\^' : '\#'}#{name}\}\}/) }.first
|
41
|
+
opening = elements.select { |e| e.text.match(/\{\{#{inverted ? '\^' : '\#'}#{name}#{condition ? " when #{condition}" : ''}\}\}/) }.first
|
41
42
|
content = []
|
42
43
|
next_sibling = opening.next
|
43
44
|
while !next_sibling.text.match(/\{\{\/#{name}\}\}/)
|
@@ -45,7 +46,7 @@ module Docstache
|
|
45
46
|
next_sibling = next_sibling.next
|
46
47
|
end
|
47
48
|
closing = next_sibling
|
48
|
-
return Block.new(name: name, data: data, opening_element: opening, content_elements: content, closing_element: closing, inverted: inverted)
|
49
|
+
return Block.new(name: name, data: data, opening_element: opening, content_elements: content, closing_element: closing, inverted: inverted, condition: condition)
|
49
50
|
end
|
50
51
|
else
|
51
52
|
raise "Block not found in given elements"
|
data/lib/docstache/data_scope.rb
CHANGED
@@ -6,24 +6,72 @@ module Docstache
|
|
6
6
|
@parent = parent
|
7
7
|
end
|
8
8
|
|
9
|
-
def get(key, hash
|
9
|
+
def get(key, hash: @data, original_key: key, condition: nil)
|
10
10
|
symbolize_keys!(hash)
|
11
11
|
tokens = key.split('.')
|
12
12
|
if tokens.length == 1
|
13
|
-
|
13
|
+
if key.match(/(\w+)\[(\d+)\]/)
|
14
|
+
result = hash.fetch($1.to_sym) { |key| @parent.get(original_key) }
|
15
|
+
if result.respond_to?(:[])
|
16
|
+
result = result[$2.to_i]
|
17
|
+
end
|
18
|
+
else
|
19
|
+
result = hash.fetch(key.to_sym) { |key| @parent.get(original_key) }
|
20
|
+
end
|
21
|
+
if condition.nil? || !result.respond_to?(:select)
|
22
|
+
return result
|
23
|
+
else
|
24
|
+
return result.select { |el| evaluate_condition(condition, el) }
|
25
|
+
end
|
14
26
|
elsif tokens.length > 1
|
15
27
|
key = tokens.shift
|
16
|
-
if
|
17
|
-
|
28
|
+
if key.match(/(\w+)\[(\d+)\]/)
|
29
|
+
if hash.has_key?($1.to_sym)
|
30
|
+
collection = hash.fetch($1.to_sym)
|
31
|
+
if collection.respond_to?(:[])
|
32
|
+
subhash = collection[$2.to_i]
|
33
|
+
else
|
34
|
+
subhash = collection
|
35
|
+
end
|
36
|
+
else
|
37
|
+
return @parent.get(original_key)
|
38
|
+
end
|
18
39
|
else
|
19
|
-
|
40
|
+
if hash.has_key?(key.to_sym)
|
41
|
+
subhash = hash.fetch(key.to_sym)
|
42
|
+
else
|
43
|
+
return @parent.get(original_key)
|
44
|
+
end
|
20
45
|
end
|
21
|
-
return get(tokens.join('.'), subhash, original_key)
|
46
|
+
return get(tokens.join('.'), hash: subhash, original_key: original_key)
|
22
47
|
end
|
23
48
|
end
|
24
49
|
|
25
50
|
private
|
26
51
|
|
52
|
+
def evaluate_condition(condition, data)
|
53
|
+
condition = condition.match(/(.+?)\s*(==|~=)\s*(.+)/)
|
54
|
+
if condition[2] == "=="
|
55
|
+
# Equality condition
|
56
|
+
left = evaluate_expression(condition[1], data)
|
57
|
+
right = evaluate_expression(condition[3], data)
|
58
|
+
return left == right
|
59
|
+
else
|
60
|
+
# Matches condition
|
61
|
+
left = get(condition[1], hash: data)
|
62
|
+
right = Regex.new(condition[3].match(/\/(.+)\//)[1])
|
63
|
+
return left.match(right)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def evaluate_expression(expression, data)
|
68
|
+
if expression.match(/(["'“])(.+)(\k<1>|”)/)
|
69
|
+
$2
|
70
|
+
else
|
71
|
+
get(expression, hash: data)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
27
75
|
def symbolize_keys!(hash)
|
28
76
|
hash.keys.each do |key|
|
29
77
|
hash[(key.to_sym rescue key)] = hash.delete(key)
|
data/lib/docstache/document.rb
CHANGED
@@ -14,12 +14,12 @@ module Docstache
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def tags
|
17
|
-
@document.text.gsub(/\s+/, '').scan(/\{\{
|
17
|
+
@document.text.gsub(/\s+/, '').scan(/\{\{.+?\}\}/)
|
18
18
|
end
|
19
19
|
|
20
20
|
def usable_tags
|
21
|
-
@document.css('w|t').select { |tag| tag.text =~ /\{\{
|
22
|
-
tag.text.scan(/\{\{
|
21
|
+
@document.css('w|t').select { |tag| tag.text =~ /\{\{.+?\}\}/ }.map { |tag|
|
22
|
+
tag.text.scan(/\{\{.+?\}\}/)
|
23
23
|
}.flatten
|
24
24
|
end
|
25
25
|
|
data/lib/docstache/renderer.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Docstache
|
2
2
|
class Renderer
|
3
|
-
BLOCK_REGEX = /\{\{([\#\^])([\w\.]+)\}\}.+?\{\{\/\
|
3
|
+
BLOCK_REGEX = /\{\{([\#\^])([\w\.]+)(?:\swhen\s(.+?\s?(?:==|~=)\s?.+?))?\}\}.+?\{\{\/\k<2>\}\}/m
|
4
4
|
|
5
5
|
def initialize(xml, data)
|
6
6
|
@content = xml
|
@@ -19,7 +19,7 @@ module Docstache
|
|
19
19
|
blocks = @content.text.scan(BLOCK_REGEX)
|
20
20
|
found_blocks = blocks.uniq.map { |block|
|
21
21
|
inverted = block[0] == "^"
|
22
|
-
Block.find_all(name: block[1], elements: @content.elements, data: @data, inverted: inverted)
|
22
|
+
Block.find_all(name: block[1], elements: @content.elements, data: @data, inverted: inverted, condition: block[2])
|
23
23
|
}.flatten
|
24
24
|
found_blocks.each do |block|
|
25
25
|
expand_and_replace_block(block)
|
@@ -40,7 +40,7 @@ module Docstache
|
|
40
40
|
block.content_elements.each(&:unlink)
|
41
41
|
end
|
42
42
|
when :loop
|
43
|
-
set = @data.get(block.name)
|
43
|
+
set = @data.get(block.name, condition: block.condition)
|
44
44
|
content = set.map { |item|
|
45
45
|
data = DataScope.new(item, @data)
|
46
46
|
elements = block.content_elements.map(&:clone)
|
@@ -62,10 +62,10 @@ module Docstache
|
|
62
62
|
|
63
63
|
def replace_tags(elements, data)
|
64
64
|
elements.css('w|t').each do |text_el|
|
65
|
-
if !(results = text_el.text.scan(/\{\{([\w
|
65
|
+
if !(results = text_el.text.scan(/\{\{([\w\.\[\]]+)\}\}/).flatten).empty?
|
66
66
|
rendered_string = text_el.text
|
67
67
|
results.each do |r|
|
68
|
-
rendered_string.gsub!(
|
68
|
+
rendered_string.gsub!("{{#{r}}}", text(data.get(r)))
|
69
69
|
end
|
70
70
|
text_el.content = rendered_string
|
71
71
|
end
|
data/lib/docstache/version.rb
CHANGED
data/lib/docstache.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
require 'nokogiri'
|
2
2
|
require 'zip'
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
require_relative "docstache/version"
|
5
|
+
require_relative "docstache/data_scope"
|
6
|
+
require_relative "docstache/block"
|
7
|
+
require_relative "docstache/renderer"
|
8
|
+
require_relative "docstache/document"
|
9
9
|
|
10
10
|
module Docstache
|
11
11
|
#noop
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: docstache
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Will Cosgrove
|
@@ -14,42 +14,42 @@ dependencies:
|
|
14
14
|
name: nokogiri
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - ~>
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '1.6'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - ~>
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.6'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rubyzip
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - ~>
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '1.1'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - ~>
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '1.1'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - ~>
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: 3.1.0
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - ~>
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: 3.1.0
|
55
55
|
description: Integrates data into MS Word docx template files. Processing supports
|
@@ -60,7 +60,7 @@ executables: []
|
|
60
60
|
extensions: []
|
61
61
|
extra_rdoc_files: []
|
62
62
|
files:
|
63
|
-
- .gitignore
|
63
|
+
- ".gitignore"
|
64
64
|
- Gemfile
|
65
65
|
- LICENSE.txt
|
66
66
|
- README.md
|
@@ -90,17 +90,17 @@ require_paths:
|
|
90
90
|
- lib
|
91
91
|
required_ruby_version: !ruby/object:Gem::Requirement
|
92
92
|
requirements:
|
93
|
-
- -
|
93
|
+
- - ">="
|
94
94
|
- !ruby/object:Gem::Version
|
95
95
|
version: '0'
|
96
96
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
97
|
requirements:
|
98
|
-
- -
|
98
|
+
- - ">="
|
99
99
|
- !ruby/object:Gem::Version
|
100
100
|
version: '0'
|
101
101
|
requirements: []
|
102
102
|
rubyforge_project:
|
103
|
-
rubygems_version: 2.
|
103
|
+
rubygems_version: 2.4.5
|
104
104
|
signing_key:
|
105
105
|
specification_version: 4
|
106
106
|
summary: Merges Hash of Data into Word docx template files using mustache syntax
|