docstache 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4663953840e841ea911fdd47ba74cb5bd4ef5f37
4
- data.tar.gz: 1b7d7b96dad91ec189f742a6f575bc3dd0b4a298
3
+ metadata.gz: 3b400a5b0a023a3d6a9deb3835faff68ee17a5d7
4
+ data.tar.gz: 59c5ff97e4c9f34aad5c38a793bf937efcf4aa80
5
5
  SHA512:
6
- metadata.gz: f1bdf1f42ad5f50efe553cb65d678ee0047889179e41c4359611100ca363238761fcfe8dfa6903b5301093bf36ed23bb5c346ae84114d04ba6c7875e51d90371
7
- data.tar.gz: e37304fd77b542fb41efde67a4ea600e1d709f36a2f918bccd60a9efce9dde1e943d066da2c9b18d38cc10d70429e354a769ea2d3fca506e082c32d0b812073b
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
- * [08f09d19] Hash keys inside DataScope are symbolized
10
+ * [08f09d1922e73ccaf17989a568deeb2ce0ebd4b8] Hash keys inside DataScope are symbolized
6
11
 
7
12
  ## 0.0.6
8
13
 
9
- * [fcba2080] Fixed a bug When two tags were inside one xml node, it would mistakenly report that there was an error when there wasn't.
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
 
@@ -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}\}\}.+\{\{\/#{name}\}\}/m)
35
- if elements.any? { |e| e.text.match(/\{\{#{inverted ? '\^' : '\#'}#{name}\}\}.+\{\{\/#{name}\}\}/m) }
36
- matches = elements.select { |e| e.text.match(/\{\{#{inverted ? '\^' : '\#'}#{name}\}\}.+\{\{\/#{name}\}\}/m) }
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"
@@ -6,24 +6,72 @@ module Docstache
6
6
  @parent = parent
7
7
  end
8
8
 
9
- def get(key, hash=@data, original_key=key)
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
- return hash.fetch(key.to_sym) { |key| @parent.get(original_key) }
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 hash.has_key?(key.to_sym)
17
- subhash = hash.fetch(key.to_sym)
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
- return @parent.get(original_key)
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)
@@ -14,12 +14,12 @@ module Docstache
14
14
  end
15
15
 
16
16
  def tags
17
- @document.text.gsub(/\s+/, '').scan(/\{\{[\w\.\^\#\/]+\}\}/)
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 =~ /\{\{[\w\.\^\#\/]+\}\}/ }.map { |tag|
22
- tag.text.scan(/\{\{[\w\.\^\#\/]+\}\}/)
21
+ @document.css('w|t').select { |tag| tag.text =~ /\{\{.+?\}\}/ }.map { |tag|
22
+ tag.text.scan(/\{\{.+?\}\}/)
23
23
  }.flatten
24
24
  end
25
25
 
@@ -1,6 +1,6 @@
1
1
  module Docstache
2
2
  class Renderer
3
- BLOCK_REGEX = /\{\{([\#\^])([\w\.]+)\}\}.+?\{\{\/\g<2>\}\}/m
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\.]+)\}\}/).flatten).empty?
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!(/\{\{#{r}\}\}/, text(data.get(r)))
68
+ rendered_string.gsub!("{{#{r}}}", text(data.get(r)))
69
69
  end
70
70
  text_el.content = rendered_string
71
71
  end
@@ -1,3 +1,3 @@
1
1
  module Docstache
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/docstache.rb CHANGED
@@ -1,11 +1,11 @@
1
1
  require 'nokogiri'
2
2
  require 'zip'
3
3
 
4
- require "docstache/version"
5
- require "docstache/data_scope"
6
- require "docstache/block"
7
- require "docstache/renderer"
8
- require "docstache/document"
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.1.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.0.14
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