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 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