sablon 0.0.9 → 0.0.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +0 -1
- data/Gemfile.lock +27 -0
- data/README.md +1 -1
- data/bin/rake +16 -0
- data/{bin → exe}/sablon +0 -0
- data/lib/sablon/content.rb +53 -0
- data/lib/sablon/context.rb +2 -2
- data/lib/sablon/operations.rb +1 -10
- data/lib/sablon/version.rb +1 -1
- data/lib/sablon.rb +2 -6
- data/sablon.gemspec +1 -1
- data/test/content_test.rb +74 -6
- data/test/context_test.rb +2 -2
- data/test/executable_test.rb +1 -1
- data/test/fixtures/shopping_list_context.json +1 -1
- data/test/mail_merge_parser_test.rb +2 -2
- data/test/sablon_test.rb +1 -1
- metadata +9 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1c8b7cc35ce1718d11e3ebc44d2b50e5a03b1575
|
4
|
+
data.tar.gz: 003512773f3372b9ed1243a4a7fd88ac301dafcb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ad54b7f87dc83a60b77fb3559d756d1798197f264618195e11796c0cd0cd71bea955991b5f7d01aa2ad668c4afbed0f2c9eaf16c0b28a3d693b0bb2c4cbe891a
|
7
|
+
data.tar.gz: 4c45533f60f2cf77b7d17be0ad77a3180fc17c3c6257178963229d1374bc8eef0d31024a110e8a9b11b4b768e451a4d04f674d0113b696a6d102cc4f8b16cdd6
|
data/.gitignore
CHANGED
data/Gemfile.lock
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
sablon (0.0.10)
|
5
|
+
nokogiri (>= 1.6.0)
|
6
|
+
rubyzip (>= 1.1)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
mini_portile (0.6.2)
|
12
|
+
minitest (5.5.1)
|
13
|
+
nokogiri (1.6.6.2)
|
14
|
+
mini_portile (~> 0.6.0)
|
15
|
+
rake (10.4.2)
|
16
|
+
rubyzip (1.1.7)
|
17
|
+
xml-simple (1.1.5)
|
18
|
+
|
19
|
+
PLATFORMS
|
20
|
+
ruby
|
21
|
+
|
22
|
+
DEPENDENCIES
|
23
|
+
bundler (>= 1.6)
|
24
|
+
minitest (~> 5.4)
|
25
|
+
rake (~> 10.0)
|
26
|
+
sablon!
|
27
|
+
xml-simple
|
data/README.md
CHANGED
@@ -90,7 +90,7 @@ word_processing_ml = <<-XML
|
|
90
90
|
</w:p>
|
91
91
|
XML
|
92
92
|
context = {
|
93
|
-
long_description: Sablon.word_ml
|
93
|
+
long_description: Sablon.content(:word_ml, word_processing_ml)
|
94
94
|
}
|
95
95
|
template.render_to_file File.expand_path("~/Desktop/output.docx"), context
|
96
96
|
```
|
data/bin/rake
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# This file was generated by Bundler.
|
4
|
+
#
|
5
|
+
# The application 'rake' is installed as part of a gem, and
|
6
|
+
# this file is here to facilitate running it.
|
7
|
+
#
|
8
|
+
|
9
|
+
require 'pathname'
|
10
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
|
11
|
+
Pathname.new(__FILE__).realpath)
|
12
|
+
|
13
|
+
require 'rubygems'
|
14
|
+
require 'bundler/setup'
|
15
|
+
|
16
|
+
load Gem.bin_path('rake', 'rake')
|
data/{bin → exe}/sablon
RENAMED
File without changes
|
data/lib/sablon/content.rb
CHANGED
@@ -1,7 +1,55 @@
|
|
1
1
|
module Sablon
|
2
2
|
module Content
|
3
|
+
class << self
|
4
|
+
def wrap(value)
|
5
|
+
case value
|
6
|
+
when Sablon::Content
|
7
|
+
value
|
8
|
+
else
|
9
|
+
if type = type_wrapping(value)
|
10
|
+
type.new(value)
|
11
|
+
else
|
12
|
+
raise ArgumentError, "Could not find Sablon content type to wrap #{value.inspect}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def make(type_id, *args)
|
18
|
+
if types.key?(type_id)
|
19
|
+
types[type_id].new(*args)
|
20
|
+
else
|
21
|
+
raise ArgumentError, "Could not find Sablon content type with id '#{type_id}'"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def register(content_type)
|
26
|
+
types[content_type.id] = content_type
|
27
|
+
end
|
28
|
+
|
29
|
+
def remove(content_type_or_id)
|
30
|
+
types.delete_if {|k,v| k == content_type_or_id || v == content_type_or_id }
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
def type_wrapping(value)
|
35
|
+
types.values.reverse.detect { |type| type.wraps?(value) }
|
36
|
+
end
|
37
|
+
|
38
|
+
def types
|
39
|
+
@types ||= {}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
3
43
|
class String < Struct.new(:string)
|
4
44
|
include Sablon::Content
|
45
|
+
def self.id; :string end
|
46
|
+
def self.wraps?(value)
|
47
|
+
value.respond_to?(:to_s)
|
48
|
+
end
|
49
|
+
|
50
|
+
def initialize(value)
|
51
|
+
super value.to_s
|
52
|
+
end
|
5
53
|
|
6
54
|
def append_to(paragraph, display_node)
|
7
55
|
string.scan(/[^\n]+|\n/).reverse.each do |part|
|
@@ -18,6 +66,8 @@ module Sablon
|
|
18
66
|
|
19
67
|
class WordML < Struct.new(:xml)
|
20
68
|
include Sablon::Content
|
69
|
+
def self.id; :word_ml end
|
70
|
+
def self.wraps?(value) false end
|
21
71
|
|
22
72
|
def append_to(paragraph, display_node)
|
23
73
|
Nokogiri::XML.fragment(xml).children.reverse.each do |child|
|
@@ -26,5 +76,8 @@ module Sablon
|
|
26
76
|
paragraph.remove
|
27
77
|
end
|
28
78
|
end
|
79
|
+
|
80
|
+
register Sablon::Content::String
|
81
|
+
register Sablon::Content::WordML
|
29
82
|
end
|
30
83
|
end
|
data/lib/sablon/context.rb
CHANGED
data/lib/sablon/operations.rb
CHANGED
@@ -3,16 +3,7 @@ module Sablon
|
|
3
3
|
module Statement
|
4
4
|
class Insertion < Struct.new(:expr, :field)
|
5
5
|
def evaluate(context)
|
6
|
-
field.replace(
|
7
|
-
end
|
8
|
-
|
9
|
-
private
|
10
|
-
def wrap_content(value)
|
11
|
-
if value.is_a?(Sablon::Content)
|
12
|
-
value
|
13
|
-
else
|
14
|
-
Sablon.string(value)
|
15
|
-
end
|
6
|
+
field.replace(Sablon::Content.wrap(expr.evaluate(context)))
|
16
7
|
end
|
17
8
|
end
|
18
9
|
|
data/lib/sablon/version.rb
CHANGED
data/lib/sablon.rb
CHANGED
@@ -18,11 +18,7 @@ module Sablon
|
|
18
18
|
Template.new(path)
|
19
19
|
end
|
20
20
|
|
21
|
-
def self.
|
22
|
-
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.string(object)
|
26
|
-
Sablon::Content::String.new(object.to_s)
|
21
|
+
def self.content(type, *args)
|
22
|
+
Content.make(type, *args)
|
27
23
|
end
|
28
24
|
end
|
data/sablon.gemspec
CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.add_runtime_dependency 'nokogiri'
|
21
|
+
spec.add_runtime_dependency 'nokogiri', ">= 1.6.0"
|
22
22
|
spec.add_runtime_dependency 'rubyzip', ">= 1.1"
|
23
23
|
|
24
24
|
spec.add_development_dependency "bundler", ">= 1.6"
|
data/test/content_test.rb
CHANGED
@@ -1,6 +1,74 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
require "test_helper"
|
3
3
|
|
4
|
+
class ContentTest < Sablon::TestCase
|
5
|
+
def test_can_build_content_objects
|
6
|
+
content = Sablon.content(:string, "a string")
|
7
|
+
assert_instance_of Sablon::Content::String, content
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_raises_error_when_building_non_registered_type
|
11
|
+
e = assert_raises ArgumentError do
|
12
|
+
Sablon.content :nope, "this should not work"
|
13
|
+
end
|
14
|
+
assert_equal "Could not find Sablon content type with id 'nope'", e.message
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_wraps_string_objects
|
18
|
+
content = Sablon::Content.wrap(67)
|
19
|
+
assert_instance_of Sablon::Content::String, content
|
20
|
+
assert_equal "67", content.string
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_raises_an_error_if_no_wrapping_type_was_found
|
24
|
+
Sablon::Content.remove Sablon::Content::String
|
25
|
+
|
26
|
+
e = assert_raises ArgumentError do
|
27
|
+
Sablon::Content.wrap(43)
|
28
|
+
end
|
29
|
+
assert_equal "Could not find Sablon content type to wrap 43", e.message
|
30
|
+
ensure
|
31
|
+
Sablon::Content.register Sablon::Content::String
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_does_not_wrap_content_objects
|
35
|
+
original_content = Sablon.content(:word_ml, "<w:p></w:p>")
|
36
|
+
content = Sablon::Content.wrap(original_content)
|
37
|
+
assert_instance_of Sablon::Content::WordML, content
|
38
|
+
assert_equal original_content.object_id, content.object_id
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class CustomContentTest < Sablon::TestCase
|
43
|
+
class MyContent < Struct.new(:numeric)
|
44
|
+
include Sablon::Content
|
45
|
+
def self.id; :custom end
|
46
|
+
def self.wraps?(value); Numeric === value end
|
47
|
+
|
48
|
+
def append_to(paragraph, display_node)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def setup
|
53
|
+
Sablon::Content.register MyContent
|
54
|
+
end
|
55
|
+
|
56
|
+
def teardown
|
57
|
+
Sablon::Content.remove MyContent
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_can_build_custom_content
|
61
|
+
content = Sablon.content(:custom, 42)
|
62
|
+
assert_instance_of MyContent, content
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_wraps_custom_content
|
66
|
+
content = Sablon::Content.wrap(31)
|
67
|
+
assert_instance_of MyContent, content
|
68
|
+
assert_equal 31, content.numeric
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
4
72
|
module ContentTestSetup
|
5
73
|
def setup
|
6
74
|
super
|
@@ -20,7 +88,7 @@ class ContentStringTest < Sablon::TestCase
|
|
20
88
|
include ContentTestSetup
|
21
89
|
|
22
90
|
def test_single_line_string
|
23
|
-
Sablon.string
|
91
|
+
Sablon.content(:string, "a normal string").append_to @paragraph, @node
|
24
92
|
|
25
93
|
output = <<-XML.strip
|
26
94
|
<w:p><span>template</span><span>a normal string</span></w:p><w:p>AFTER</w:p>
|
@@ -29,7 +97,7 @@ class ContentStringTest < Sablon::TestCase
|
|
29
97
|
end
|
30
98
|
|
31
99
|
def test_numeric_string
|
32
|
-
Sablon.string
|
100
|
+
Sablon.content(:string, 42).append_to @paragraph, @node
|
33
101
|
|
34
102
|
output = <<-XML.strip
|
35
103
|
<w:p><span>template</span><span>42</span></w:p><w:p>AFTER</w:p>
|
@@ -38,7 +106,7 @@ class ContentStringTest < Sablon::TestCase
|
|
38
106
|
end
|
39
107
|
|
40
108
|
def test_string_with_newlines
|
41
|
-
Sablon.string
|
109
|
+
Sablon.content(:string, "a\nmultiline\n\nstring").append_to @paragraph, @node
|
42
110
|
|
43
111
|
output = <<-XML.strip.gsub("\n", "")
|
44
112
|
<w:p>
|
@@ -57,7 +125,7 @@ class ContentStringTest < Sablon::TestCase
|
|
57
125
|
end
|
58
126
|
|
59
127
|
def test_blank_string
|
60
|
-
Sablon.string
|
128
|
+
Sablon.content(:string, "").append_to @paragraph, @node
|
61
129
|
|
62
130
|
assert_xml_equal @template_text, @document
|
63
131
|
end
|
@@ -67,14 +135,14 @@ class ContentWordMLTest < Sablon::TestCase
|
|
67
135
|
include ContentTestSetup
|
68
136
|
|
69
137
|
def test_blank_word_ml
|
70
|
-
Sablon.word_ml
|
138
|
+
Sablon.content(:word_ml, "").append_to @paragraph, @node
|
71
139
|
|
72
140
|
assert_xml_equal "<w:p>AFTER</w:p>", @document
|
73
141
|
end
|
74
142
|
|
75
143
|
def test_inserts_word_ml_into_the_document
|
76
144
|
@word_ml = '<w:p><w:r><w:t xml:space="preserve">a </w:t></w:r></w:p>'
|
77
|
-
Sablon.word_ml
|
145
|
+
Sablon.content(:word_ml, @word_ml).append_to @paragraph, @node
|
78
146
|
|
79
147
|
output = <<-XML.strip.gsub("\n", "")
|
80
148
|
<w:p>
|
data/test/context_test.rb
CHANGED
@@ -8,8 +8,8 @@ class ContextTest < Sablon::TestCase
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def test_recognizes_wordml_keys
|
11
|
-
transformed = Sablon::Context.transform({"
|
12
|
-
assert_equal({ "mykey"=>Sablon.word_ml
|
11
|
+
transformed = Sablon::Context.transform({"word_ml:mykey" => "<w:p><w:p>", "otherkey" => "<nope>"})
|
12
|
+
assert_equal({ "mykey"=>Sablon.content(:word_ml, "<w:p><w:p>"),
|
13
13
|
"otherkey"=>"<nope>"}, transformed)
|
14
14
|
end
|
15
15
|
end
|
data/test/executable_test.rb
CHANGED
@@ -9,7 +9,7 @@ class ExecutableTest < Sablon::TestCase
|
|
9
9
|
@output_path = @base_path + "sandbox/shopping_list.docx"
|
10
10
|
@template_path = @base_path + "fixtures/shopping_list_template.docx"
|
11
11
|
@context_path = @base_path + "fixtures/shopping_list_context.json"
|
12
|
-
@executable_path = @base_path + '../
|
12
|
+
@executable_path = @base_path + '../exe/sablon'
|
13
13
|
|
14
14
|
@output_path.delete if @output_path.exist?
|
15
15
|
end
|
@@ -5,7 +5,7 @@
|
|
5
5
|
"first_name": "John",
|
6
6
|
"last_name": "Doe"
|
7
7
|
},
|
8
|
-
"
|
8
|
+
"word_ml:description": "<w:p><w:r><w:t xml:space=\"preserve\">A list of items to buy at the next </w:t></w:r><w:r><w:rPr><w:b /></w:rPr><w:t>Shop</w:t></w:r><w:r><w:t xml:space=\"preserve\">.</w:t></w:r></w:p>"
|
9
9
|
},
|
10
10
|
"items": [
|
11
11
|
{"name": "Milk", "amount": "1L"},
|
@@ -35,7 +35,7 @@ module MailMergeParser
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def test_replace
|
38
|
-
field.replace(Sablon.string
|
38
|
+
field.replace(Sablon.content(:string, "Hello"))
|
39
39
|
xml = <<-xml.strip
|
40
40
|
<w:p>
|
41
41
|
<w:r w:rsidR=\"004B49F0\">
|
@@ -70,7 +70,7 @@ xml
|
|
70
70
|
end
|
71
71
|
|
72
72
|
def test_replace
|
73
|
-
field.replace(Sablon.string
|
73
|
+
field.replace(Sablon.content(:string, "Hello"))
|
74
74
|
xml = <<-xml.strip
|
75
75
|
<w:p>
|
76
76
|
|
data/test/sablon_test.rb
CHANGED
@@ -23,7 +23,7 @@ class SablonTest < Sablon::TestCase
|
|
23
23
|
author: "Yves Senn",
|
24
24
|
title: "Letter of application",
|
25
25
|
person: person,
|
26
|
-
about_me: Sablon.word_ml
|
26
|
+
about_me: Sablon.content(:word_ml, snippet("about_me_snippet").strip),
|
27
27
|
items: [item.new("1.", "Ruby", "★" * 5), item.new("2.", "Java", "★" * 1), item.new("3.", "Python", "★" * 3)],
|
28
28
|
career: [position.new("1999 - 2006", "Junior Java Engineer", "Lorem ipsum dolor\nsit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."),
|
29
29
|
position.new("2006 - 2013", "Senior Ruby Developer", "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo."),
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sablon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yves Senn
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-04-
|
11
|
+
date: 2015-04-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 1.6.0
|
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
|
-
version:
|
26
|
+
version: 1.6.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rubyzip
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -99,17 +99,19 @@ description: Sablon is a document template processor. At this time it works only
|
|
99
99
|
email:
|
100
100
|
- yves.senn@gmail.com
|
101
101
|
executables:
|
102
|
-
-
|
102
|
+
- rake
|
103
103
|
extensions: []
|
104
104
|
extra_rdoc_files: []
|
105
105
|
files:
|
106
106
|
- ".gitignore"
|
107
107
|
- ".travis.yml"
|
108
108
|
- Gemfile
|
109
|
+
- Gemfile.lock
|
109
110
|
- LICENSE.txt
|
110
111
|
- README.md
|
111
112
|
- Rakefile
|
112
|
-
- bin/
|
113
|
+
- bin/rake
|
114
|
+
- exe/sablon
|
113
115
|
- lib/sablon.rb
|
114
116
|
- lib/sablon/content.rb
|
115
117
|
- lib/sablon/context.rb
|
@@ -175,7 +177,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
175
177
|
version: '0'
|
176
178
|
requirements: []
|
177
179
|
rubyforge_project:
|
178
|
-
rubygems_version: 2.4.
|
180
|
+
rubygems_version: 2.4.6
|
179
181
|
signing_key:
|
180
182
|
specification_version: 4
|
181
183
|
summary: docx tempalte processor
|