odt-serenity 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 78d869d91c4ce61e0894727676277786bac24d90a55faaba90d8124f7b009af6
4
+ data.tar.gz: 9fb183858137444a556fefb79a7caad6feb2375e997b45f5405e2640c0dbdc7d
5
+ SHA512:
6
+ metadata.gz: 4c73043b050e81872efa7d3439082dffde2c77467112312083807639d5b7ff3097e001c4311a493bad5b272ca2c37d1000f03dabb16e9c36d7e4091a905f4777
7
+ data.tar.gz: e6021fc220675d29be8df904ce7e8a2e5cf34cc9a22cbe5ea6a042faf3369da0182e0856007e1a394b604be5d111986c00a2be619eb2b0fdeb2a3d5ea0274936
data/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ Copyright (c) 2010 Tomas Kramar
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
23
+
data/README.md ADDED
@@ -0,0 +1,74 @@
1
+ Serenity is an embedded ruby for OpenOffice documents (.odt files). You provide an .odt template with ruby code inside a special markup and the data and Serenity generates the document. If you know erb all of this should sound familiar.
2
+
3
+ Important Changes
4
+ =================
5
+
6
+ As of version 0.2.0 serenity is using instance variables in the templates. In previous versions, your instance variables would be converted to local before passing to the template, so while in the code you had `@title = 'Serenity'`, you had to put `{%= title }` in the template to get serenity to work. This has now changed and you need to use instance variables in the templates: `{%= @title }`. Honestly, I don't know why I did it this way in the first place, considering that people are used to instance variables in templates from rails.
7
+
8
+ Usage
9
+ ======
10
+
11
+ Serenity is best demonstrated with an example. The first picture shows the template with the ruby code, next image shows the generated document. The template, output and the sample script can be found in the showcase directory.
12
+
13
+ ![Serenity template](http://github.com/kremso/serenity/blob/master/showcase/imgs/serenity_template.png?raw=true)
14
+
15
+ The image above is a screenshot of showcase.odt from the [showcase](http://github.com/kremso/serenity/blob/master/showcase) directory. It's a regular OpenOffice document with ruby code embedded inside a special markup. That ruby code drives the document creation. You can use conditionals, loops, blocks — in fact, the whole ruby language and you can apply any OpenOffice formatting to the outputted variables or static text.
16
+
17
+ The second line in the template is `{%= @title%}` what means: output the value of variable title. It's bold and big, in fact, it's has the 'Heading 1' style applied. That variable will be replaced in the generated document, but it will still be a 'Heading 1'.
18
+
19
+ You can now take that template, provide the data and generate the final document:
20
+
21
+ require 'rubygems'
22
+ require 'serenity'
23
+
24
+ class Showcase
25
+ include Serenity::Generator
26
+
27
+ Person = Struct.new(:name, :items)
28
+ Item = Struct.new(:name, :usage)
29
+
30
+ def generate_showcase
31
+ @title = 'Serenity inventory'
32
+
33
+ mals_items = [Item.new('Moses Brothers Self-Defense Engine Frontier Model B', 'Lock and load')]
34
+ mal = Person.new('Malcolm Reynolds', mals_items)
35
+
36
+ jaynes_items = [Item.new('Vera', 'Callahan full-bore auto-lock with a customized trigger, double cartridge and thorough gauge'),
37
+ Item.new('Lux', 'Ratatata'),
38
+ Item.new('Knife', 'Cut-throat')]
39
+ jayne = Person.new('Jayne Cobb', jaynes_items)
40
+
41
+ @crew = [mal, jayne]
42
+
43
+ render_odt 'showcase.odt'
44
+ end
45
+ end
46
+
47
+ The key parts are `include Serenity::Generator` and `render_odt`. The data for the template must be provided as instance variables.
48
+
49
+ Following picture shows the generated document. It's a screenshot of the showcase_output.odt document from the [showcase](http://github.com/kremso/serenity/blob/master/showcase) directory.
50
+
51
+ ![Generated document](http://github.com/kremso/serenity/blob/master/showcase/imgs/serenity_output.png?raw=true)
52
+
53
+ Installation
54
+ ============
55
+
56
+ gem install serenity-odt
57
+
58
+ Yeah, serenity is already taken on gemcutter.
59
+
60
+ Creating templates
61
+ ===================
62
+
63
+ Templates are created directly in OpenOffice. Ruby code is enclosed in special markup:
64
+
65
+ + `{%= %}` is for ruby code which should be output to the final document. `to_s` is applied to anything found inside this markup
66
+ + `{% %}` is for everything else — loops, ifs, ends and any other non-outputting code
67
+
68
+ Any special formatting should by applied directly on the markup. E.g. if you need to ouput the value of variable title in bold font, write `{%= title %}`, select in in OpenOffice and make it bold. See the showcase.odt for more examples.
69
+
70
+ Contact
71
+ =======
72
+
73
+ kramar[dot]tomas[at]gmail.com
74
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1 @@
1
+ require_relative './serenity'
@@ -0,0 +1,19 @@
1
+ module Serenity
2
+ module Debug
3
+ def debug?
4
+ false
5
+ end
6
+
7
+ def debug_file_path
8
+ File.join(debug_dir, debug_file_name)
9
+ end
10
+
11
+ def debug_file_name
12
+ "serenity_debug_#{rand(100)}.rb"
13
+ end
14
+
15
+ def debug_dir
16
+ File.join(File.dirname(__FILE__), '..', '..', 'debug')
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,18 @@
1
+ class String
2
+ def escape_xml
3
+ mgsub!([[/&/, '&amp;'], [/</, '&lt;'], [/>/, '&gt;']])
4
+ end
5
+
6
+ def convert_newlines
7
+ gsub!("\n", '<text:line-break/>')
8
+ self
9
+ end
10
+
11
+ def mgsub!(key_value_pairs=[].freeze)
12
+ regexp_fragments = key_value_pairs.collect { |k,v| k }
13
+ gsub!(Regexp.union(*regexp_fragments)) do |match|
14
+ key_value_pairs.detect{|k,v| k =~ match}[1]
15
+ end
16
+ self
17
+ end
18
+ end
@@ -0,0 +1,22 @@
1
+ module Serenity
2
+ module Generator
3
+ def render_odt template_path, output_path = output_name(template_path)
4
+ template = Template.new template_path, output_path
5
+ template.process binding
6
+ end
7
+
8
+ def helper
9
+ @helper ||= Serenity::Helper.new
10
+ end
11
+
12
+ private
13
+
14
+ def output_name input
15
+ if input =~ /(.+)\.odt\Z/
16
+ "#{$1}_output.odt"
17
+ else
18
+ "#{input}_output.odt"
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,7 @@
1
+ require_relative './helpers/tables_helper'
2
+
3
+ module Serenity
4
+ class Helper
5
+ include TablesHelper
6
+ end
7
+ end
@@ -0,0 +1,13 @@
1
+ module Serenity
2
+ module TablesHelper
3
+ # TODO: Fix static name of variable #builder
4
+ def merge_rows_tag(items, col:)
5
+ items.each_with_index do |item, index|
6
+ yield(
7
+ item,
8
+ OpenStruct.new(subject: item, index: index, count: items.count)
9
+ )
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,32 @@
1
+ module Serenity
2
+ class ImagesProcessor
3
+ include Debug
4
+
5
+ IMAGE_DIR_NAME = "Pictures"
6
+
7
+ def initialize(xml_content, context)
8
+ @replacements = []
9
+ @images = eval('@images', context)
10
+ @xml_content = xml_content
11
+ end
12
+
13
+ def generate_replacements
14
+ require 'nokogiri'
15
+
16
+ if @images && @images.kind_of?(Hash)
17
+ xml_data = Nokogiri::XML(@xml_content)
18
+
19
+ @images.each do |image_name, replacement_path|
20
+ if node = xml_data.xpath("//draw:frame[@draw:name='#{image_name}']/draw:image").first
21
+ placeholder_path = node.attribute('href').value
22
+ odt_image_path = ::File.join(IMAGE_DIR_NAME, ::File.basename(placeholder_path))
23
+
24
+ @replacements << [odt_image_path, replacement_path]
25
+ end
26
+ end
27
+ end
28
+
29
+ @replacements
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,81 @@
1
+ module Serenity
2
+ class Line
3
+ attr_reader :text
4
+
5
+ def initialize text
6
+ @text = text
7
+ end
8
+
9
+ def to_s
10
+ @text
11
+ end
12
+
13
+ def clone
14
+ self.class.new(text)
15
+ end
16
+
17
+ def self.text txt
18
+ TextLine.new txt
19
+ end
20
+
21
+ def self.code txt
22
+ CodeLine.new txt
23
+ end
24
+
25
+ def self.string txt
26
+ StringLine.new txt
27
+ end
28
+
29
+ def self.literal txt
30
+ LiteralLine.new txt
31
+ end
32
+
33
+ end
34
+
35
+ class TextLine < Line
36
+ def to_buf
37
+ " _buf << '" << escape_text(@text) << "';"
38
+ end
39
+
40
+ def escape_text text
41
+ text.gsub(/['\\]/, '\\\\\&')
42
+ end
43
+
44
+ def set_attribute(key, val)
45
+ tag = Nokogiri.XML(@text).children[0]
46
+ tag[key] = val
47
+
48
+ updated_text = tag.to_s
49
+ updated_text.gsub!('/','') unless @text.include?('/')
50
+
51
+ @text = updated_text
52
+ end
53
+ end
54
+
55
+ class CodeLine < Line
56
+ def to_buf
57
+ escape_code(@text) << ';'
58
+ end
59
+
60
+ def escape_code code
61
+ code.mgsub! [[/&apos;/, "'"], [/&gt;/, '>'], [/&lt/, '<'], [/&quot;/, '"'], [/&amp;/, '&']]
62
+ end
63
+ end
64
+
65
+ class StringLine < CodeLine
66
+ def to_buf
67
+ " _buf << (" << escape_code(@text) << ").to_s.escape_xml.convert_newlines;"
68
+ end
69
+
70
+ def convert_newlines text
71
+ text.gsub("First line", '<text:line-break>')
72
+ end
73
+ end
74
+
75
+ class LiteralLine < CodeLine
76
+ def to_buf
77
+ " _buf << (" << escape_code(@text) << ").to_s;"
78
+ end
79
+ end
80
+
81
+ end
@@ -0,0 +1,7 @@
1
+ module Serenity
2
+ class NodeType
3
+ TAG = 1
4
+ CONTROL = 2
5
+ TEMPLATE = 3
6
+ end
7
+ end
@@ -0,0 +1,112 @@
1
+ module Serenity
2
+ class OdtEruby
3
+ include Debug
4
+
5
+ EMBEDDED_PATTERN = /\{%([=%]+)?(.*?)-?%\}/m
6
+
7
+ attr_reader :template
8
+
9
+ def initialize template
10
+ @template = template
11
+ end
12
+
13
+ def src
14
+ @src ||= begin
15
+ script = convert_to_ruby_script template
16
+
17
+ if debug?
18
+ File.open(debug_file_path, 'w') { |f| f << script }
19
+ end
20
+
21
+ script
22
+ end
23
+ end
24
+
25
+ def evaluate context
26
+ encoding_src = src.force_encoding Encoding.default_external
27
+ eval(encoding_src, context)
28
+ end
29
+
30
+ def raw_lines
31
+ @sugar_lines ||= convert_to_raw_lines template
32
+ end
33
+
34
+ def lines
35
+ @lines ||= SyntacticSugar.all.translate(raw_lines)
36
+ end
37
+
38
+ private
39
+
40
+ def convert_to_ruby_script(template)
41
+ src = "_buf = '';"
42
+ lines.each { |line| src << line.to_buf }
43
+ src << "\n_buf.to_s\n"
44
+ end
45
+
46
+ def convert_to_raw_lines(template)
47
+ buffer = []
48
+ buffer_next = []
49
+
50
+ template.each_node do |node, type|
51
+ if !buffer_next.empty?
52
+ if is_matching_pair?(buffer.last, node)
53
+ buffer.pop
54
+ next
55
+ elsif is_nonpair_tag? node
56
+ next
57
+ else
58
+ buffer << buffer_next
59
+ buffer.flatten!
60
+ buffer_next = []
61
+ end
62
+ end
63
+
64
+ if type == NodeType::CONTROL
65
+ buffer_next = process_instruction(node)
66
+ else
67
+ buffer << process_instruction(node)
68
+ buffer.flatten!
69
+ end
70
+ end
71
+
72
+ buffer
73
+ end
74
+
75
+ def process_instruction text
76
+ #text = text.strip
77
+ pos = 0
78
+ src = []
79
+
80
+ text.scan(EMBEDDED_PATTERN) do |indicator, code|
81
+ m = Regexp.last_match
82
+ middle = text[pos...m.begin(0)]
83
+ pos = m.end(0)
84
+ src << Line.text(middle) unless middle.empty?
85
+
86
+ if !indicator # <% %>
87
+ src << Line.code(code)
88
+ elsif indicator == '=' # <%= %>
89
+ src << Line.string(code)
90
+ elsif indicator == '%' # <%% %>
91
+ src << Line.literal(code)
92
+ end
93
+ end
94
+
95
+ rest = pos == 0 ? text : text[pos..-1]
96
+
97
+ src << Line.text(rest) unless rest.nil? or rest.empty?
98
+ src
99
+ end
100
+
101
+ def is_nonpair_tag? tag
102
+ tag =~ /<.+?\/>/
103
+ end
104
+
105
+ def is_matching_pair? open, close
106
+ open = open.to_s.strip
107
+ close = close.to_s.strip
108
+
109
+ close == "</#{open[1, close.length - 3]}>"
110
+ end
111
+ end
112
+ end
@@ -0,0 +1 @@
1
+ require_relative './ruby_lexer/method.rb'
@@ -0,0 +1,24 @@
1
+ require_relative "./syntactic_sugars/application_sugar"
2
+ require_relative "./syntactic_sugars/row_sugar"
3
+
4
+ module Serenity
5
+ class SyntacticSugar
6
+ class << self
7
+ def all
8
+ new [RowSugar.new]
9
+ end
10
+ end
11
+
12
+ attr_reader :sugars
13
+
14
+ def initialize(sugars = [])
15
+ @sugars = sugars
16
+ end
17
+
18
+ def translate(lines)
19
+ sugars.inject(lines) do |output, sugar|
20
+ sugar.translate(output)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,7 @@
1
+ module Serenity
2
+ class ApplicationSugar
3
+ def translate(lines)
4
+ lines
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,119 @@
1
+ module Serenity
2
+ class RowSugar < ApplicationSugar
3
+ def translate(lines)
4
+ result = []
5
+ begin_index = nil
6
+
7
+ lines.each_with_index do |line, index|
8
+ if begin_construction? line
9
+ begin_index = index
10
+ elsif begin_index && end_construction?(line)
11
+ result += translate_construction(lines.slice(begin_index, index - begin_index + 1))
12
+ begin_index = nil
13
+ elsif begin_index.nil?
14
+ result << line
15
+ end
16
+ end
17
+
18
+ result
19
+ end
20
+
21
+ private
22
+
23
+ def begin_construction?(line)
24
+ line.is_a?(Serenity::CodeLine) && line.text.include?('merge_rows_tag')
25
+ end
26
+
27
+ def end_construction?(line)
28
+ line.is_a?(Serenity::CodeLine) && line.text.include?('end')
29
+ end
30
+
31
+ def begin_cell?(line)
32
+ line.is_a?(Serenity::TextLine) && line.text.include?('<table:table-cell')
33
+ end
34
+
35
+ def end_cell?(line)
36
+ line.is_a?(Serenity::TextLine) && line.text.include?('</table:table-cell>')
37
+ end
38
+
39
+ def add_attribute_to_other_row(lines, options)
40
+ curr_col, curr_index = 0, 0
41
+ result = []
42
+
43
+ while curr_index < lines.length
44
+ curr_col = curr_col + 1 if begin_cell? lines[curr_index]
45
+
46
+ if curr_col == options[:col]
47
+ result << Line.text("<table:covered-table-cell/>")
48
+ break
49
+ else
50
+ result << lines[curr_index]
51
+ end
52
+
53
+ curr_index = curr_index + 1
54
+ end
55
+
56
+ while curr_index < lines.length
57
+ if end_cell? lines[curr_index]
58
+ curr_index = curr_index + 1
59
+ break
60
+ end
61
+
62
+ curr_index = curr_index + 1
63
+ end
64
+
65
+ while curr_index < lines.length
66
+ result << lines[curr_index]
67
+ curr_index = curr_index + 1
68
+ end
69
+
70
+ result
71
+ end
72
+
73
+ def add_attribute_to_first_row(lines, options)
74
+ curr_col = 0
75
+
76
+ found_index = lines.index do |line|
77
+ curr_col = curr_col + 1 if begin_cell? line
78
+ curr_col == options[:col]
79
+ end
80
+
81
+ cloned_lines = lines.map(&:clone)
82
+
83
+ if found_index
84
+ cloned_lines[found_index].set_attribute 'table:number-rows-spanned', '%{rows_count}'
85
+ cloned_lines[found_index] = Line.literal("'#{cloned_lines[found_index]}' % { rows_count: builder.count }")
86
+ end
87
+
88
+ cloned_lines
89
+ end
90
+
91
+ def translate_construction(lines)
92
+ first_line, last_line = lines[0], lines[lines.length - 1]
93
+
94
+ construction_options = parse_construction_options first_line.text
95
+ construction_lines = lines.slice(1, lines.length - 2)
96
+
97
+ result = [first_line]
98
+ result << Line.code(" if builder.index == 0 ")
99
+ result += add_attribute_to_first_row(construction_lines, construction_options)
100
+ result << Line.code(" else ")
101
+ result += add_attribute_to_other_row(construction_lines, construction_options)
102
+ result << Line.code(" end ")
103
+ result << last_line
104
+
105
+ result
106
+ end
107
+
108
+ # TODO: May be add gem parser?
109
+ def parse_construction_options(text)
110
+ options = {}
111
+
112
+ if result = text.match(/col:\s(\d){1,}/)
113
+ options[:col] = result[1].to_i
114
+ end
115
+
116
+ options
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,38 @@
1
+ require 'zip'
2
+ require 'fileutils'
3
+
4
+ module Serenity
5
+ class Template
6
+ attr_accessor :template
7
+
8
+ def initialize(template, output)
9
+ FileUtils.cp(template, output)
10
+ @template = output
11
+ end
12
+
13
+ def process context
14
+ tmpfiles = []
15
+ Zip::File.open(@template) do |zipfile|
16
+ %w(content.xml styles.xml).each do |xml_file|
17
+ content = zipfile.read(xml_file)
18
+
19
+ # Images replacement
20
+ images_replacements = ImagesProcessor.new(content, context).generate_replacements
21
+ images_replacements.each do |r|
22
+ zipfile.replace(r.first, r.last)
23
+ end
24
+
25
+ odteruby = OdtEruby.new(XmlReader.new(content))
26
+ out = odteruby.evaluate(context)
27
+ out.force_encoding Encoding.default_external
28
+
29
+ tmpfiles << (file = Tempfile.new("serenity"))
30
+ file << out
31
+ file.close
32
+
33
+ zipfile.replace(xml_file, file.path)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,3 @@
1
+ module Serenity
2
+ VERSION = '3.0.0'.freeze
3
+ end
@@ -0,0 +1,31 @@
1
+ module Serenity
2
+ class XmlReader
3
+
4
+ def initialize src
5
+ @src = src.force_encoding("UTF-8")
6
+ end
7
+
8
+ def each_node
9
+ last_match_pos = 0
10
+
11
+ @src.scan(/<.*?>/) do |node|
12
+ m = Regexp.last_match
13
+ if m.begin(0) > last_match_pos
14
+ text = @src[last_match_pos...m.begin(0)]
15
+ yield text, node_type(text) if text.gsub(/\s+/, '') != ''
16
+ end
17
+
18
+ last_match_pos = m.end(0)
19
+ yield node, NodeType::TAG
20
+ end
21
+ end
22
+
23
+ def node_type text
24
+ if text =~ /\s*\{%[^=#].+?%\}\s*/
25
+ NodeType::CONTROL
26
+ else
27
+ NodeType::TEMPLATE
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1 @@
1
+ require_relative './serenity'
data/lib/serenity.rb ADDED
@@ -0,0 +1,15 @@
1
+ require 'nokogiri'
2
+ require 'ostruct'
3
+
4
+ require 'serenity/version'
5
+ require 'serenity/line'
6
+ require 'serenity/debug'
7
+ require 'serenity/node_type'
8
+ require 'serenity/escape_xml'
9
+ require 'serenity/odteruby'
10
+ require 'serenity/images_processor'
11
+ require 'serenity/template'
12
+ require 'serenity/xml_reader'
13
+ require 'serenity/helper'
14
+ require 'serenity/syntactic_sugar'
15
+ require 'serenity/generator'
metadata ADDED
@@ -0,0 +1,122 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: odt-serenity
3
+ version: !ruby/object:Gem::Version
4
+ version: 3.0.0
5
+ platform: ruby
6
+ authors:
7
+ - kremso
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-03-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rubyzip
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 1.2.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 1.2.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: nokogiri
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '1.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '1.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 1.2.9
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 1.2.9
55
+ - !ruby/object:Gem::Dependency
56
+ name: byebug
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Embedded ruby for OpenOffice/LibreOffice Text Document (.odt) files.
70
+ You provide an .odt template with ruby code in a special markup and the data, and
71
+ Serenity generates the document. Very similar to .erb files.
72
+ email: ''
73
+ executables: []
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - LICENSE
78
+ - README.md
79
+ - Rakefile
80
+ - lib/odt-serenity.rb
81
+ - lib/serenity-odt.rb
82
+ - lib/serenity.rb
83
+ - lib/serenity/debug.rb
84
+ - lib/serenity/escape_xml.rb
85
+ - lib/serenity/generator.rb
86
+ - lib/serenity/helper.rb
87
+ - lib/serenity/helpers/tables_helper.rb
88
+ - lib/serenity/images_processor.rb
89
+ - lib/serenity/line.rb
90
+ - lib/serenity/node_type.rb
91
+ - lib/serenity/odteruby.rb
92
+ - lib/serenity/ruby_lexer.rb
93
+ - lib/serenity/syntactic_sugar.rb
94
+ - lib/serenity/syntactic_sugars/application_sugar.rb
95
+ - lib/serenity/syntactic_sugars/row_sugar.rb
96
+ - lib/serenity/template.rb
97
+ - lib/serenity/version.rb
98
+ - lib/serenity/xml_reader.rb
99
+ homepage: https://github.com/mr-dxdy/serenity
100
+ licenses: []
101
+ metadata: {}
102
+ post_install_message:
103
+ rdoc_options: []
104
+ require_paths:
105
+ - lib
106
+ required_ruby_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ required_rubygems_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ requirements: []
117
+ rubygems_version: 3.1.6
118
+ signing_key:
119
+ specification_version: 4
120
+ summary: Fork of project serenity-odt. Parse ODT file and substitutes placeholders
121
+ like ERb.
122
+ test_files: []