redmine_api_helper 0.3.24
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.
Potentially problematic release.
This version of redmine_api_helper might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/.gitattributes +2 -0
- data/.gitignore +11 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/LICENSE +339 -0
- data/README.md +30 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/date_helper/date.rb +311 -0
- data/lib/odf_writer/bookmark.rb +110 -0
- data/lib/odf_writer/bookmark_reader.rb +77 -0
- data/lib/odf_writer/document.rb +372 -0
- data/lib/odf_writer/field.rb +174 -0
- data/lib/odf_writer/field_reader.rb +78 -0
- data/lib/odf_writer/image.rb +158 -0
- data/lib/odf_writer/image_reader.rb +76 -0
- data/lib/odf_writer/images.rb +89 -0
- data/lib/odf_writer/list_style.rb +331 -0
- data/lib/odf_writer/nested.rb +156 -0
- data/lib/odf_writer/odf_helper.rb +56 -0
- data/lib/odf_writer/parser/default.rb +685 -0
- data/lib/odf_writer/path_finder.rb +114 -0
- data/lib/odf_writer/section.rb +120 -0
- data/lib/odf_writer/section_reader.rb +61 -0
- data/lib/odf_writer/style.rb +417 -0
- data/lib/odf_writer/table.rb +135 -0
- data/lib/odf_writer/table_reader.rb +61 -0
- data/lib/odf_writer/template.rb +222 -0
- data/lib/odf_writer/text.rb +97 -0
- data/lib/odf_writer/text_reader.rb +77 -0
- data/lib/odf_writer/version.rb +29 -0
- data/lib/redmine_api_helper/api_helper.rb +333 -0
- data/lib/redmine_api_helper/args_helper.rb +106 -0
- data/lib/redmine_api_helper/attachments_api_helper.rb +52 -0
- data/lib/redmine_api_helper/define_api_helpers.rb +78 -0
- data/lib/redmine_api_helper/document_categories_api_helper.rb +38 -0
- data/lib/redmine_api_helper/groups_api_helper.rb +80 -0
- data/lib/redmine_api_helper/helpers.rb +50 -0
- data/lib/redmine_api_helper/issue_priorities_api_helper.rb +38 -0
- data/lib/redmine_api_helper/issue_relations_api_helper.rb +66 -0
- data/lib/redmine_api_helper/issue_statuses_api_helper.rb +36 -0
- data/lib/redmine_api_helper/issues_api_helper.rb +124 -0
- data/lib/redmine_api_helper/my_account_api_helper.rb +45 -0
- data/lib/redmine_api_helper/news_api_helper.rb +73 -0
- data/lib/redmine_api_helper/project_memberships_api_helper.rb +77 -0
- data/lib/redmine_api_helper/projects_api_helper.rb +73 -0
- data/lib/redmine_api_helper/roles_api_helper.rb +52 -0
- data/lib/redmine_api_helper/scripts_api_helper.rb +87 -0
- data/lib/redmine_api_helper/search_api_helper.rb +38 -0
- data/lib/redmine_api_helper/time_entries_api_helper.rb +73 -0
- data/lib/redmine_api_helper/time_entry_activities_api_helper.rb +38 -0
- data/lib/redmine_api_helper/trackers_api_helper.rb +38 -0
- data/lib/redmine_api_helper/users_api_helper.rb +73 -0
- data/lib/redmine_api_helper/version.rb +24 -0
- data/lib/redmine_api_helper/wiki_pages_api_helper.rb +66 -0
- data/lib/redmine_api_helper.rb +88 -0
- data/redmine_api_helper.gemspec +35 -0
- metadata +148 -0
@@ -0,0 +1,77 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# Ruby Gem to create a self populating Open Document Format (.odf) text file.
|
4
|
+
#
|
5
|
+
# Copyright 2021 Stephan Wenzel <stephan.wenzel@drwpatent.de>
|
6
|
+
#
|
7
|
+
# This program is free software; you can redistribute it and/or
|
8
|
+
# modify it under the terms of the GNU General Public License
|
9
|
+
# as published by the Free Software Foundation; either version 2
|
10
|
+
# of the License, or (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with this program; if not, write to the Free Software
|
19
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
20
|
+
#
|
21
|
+
|
22
|
+
module ODFWriter
|
23
|
+
|
24
|
+
########################################################################################
|
25
|
+
#
|
26
|
+
# BookmarkReader: find all bookmarks and set name
|
27
|
+
#
|
28
|
+
########################################################################################
|
29
|
+
class BookmarkReader
|
30
|
+
|
31
|
+
attr_accessor :name
|
32
|
+
|
33
|
+
######################################################################################
|
34
|
+
#
|
35
|
+
# initialize
|
36
|
+
#
|
37
|
+
######################################################################################
|
38
|
+
def initialize(opts={})
|
39
|
+
@name = opts[:name]
|
40
|
+
end #def
|
41
|
+
|
42
|
+
######################################################################################
|
43
|
+
#
|
44
|
+
# get_paths: limit to paths with ancestors 'text '(content.xml) and master-styles (styles.xml)
|
45
|
+
#
|
46
|
+
######################################################################################
|
47
|
+
def paths( root, doc)
|
48
|
+
|
49
|
+
# find nodes with matching field elements matching [BOOKMARK] pattern
|
50
|
+
nodes = doc.xpath("//*[self::text:bookmark or self::text:bookmark-start]").select{|node| scan(node).present? }
|
51
|
+
|
52
|
+
# find path for each field
|
53
|
+
paths = nil
|
54
|
+
nodes.each do |node|
|
55
|
+
leaf = {:bookmarks => scan(node)}
|
56
|
+
paths = PathFinder.trail(node, leaf, :root => root, :paths => paths)
|
57
|
+
end #each
|
58
|
+
paths.to_h
|
59
|
+
|
60
|
+
end #def
|
61
|
+
|
62
|
+
######################################################################################
|
63
|
+
# private
|
64
|
+
######################################################################################
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def scan(node)
|
69
|
+
if name
|
70
|
+
node.attr("text:name") == name.upcase ? [node.attr("text:name")] : []
|
71
|
+
else
|
72
|
+
[node.attr("text:name")]
|
73
|
+
end
|
74
|
+
end #def
|
75
|
+
|
76
|
+
end #class
|
77
|
+
end #module
|
@@ -0,0 +1,372 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# Ruby Gem to create a self populating Open Document Format (.odf) text file.
|
4
|
+
#
|
5
|
+
# Copyright 2021 Stephan Wenzel <stephan.wenzel@drwpatent.de>
|
6
|
+
#
|
7
|
+
# This program is free software; you can redistribute it and/or
|
8
|
+
# modify it under the terms of the GNU General Public License
|
9
|
+
# as published by the Free Software Foundation; either version 2
|
10
|
+
# of the License, or (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with this program; if not, write to the Free Software
|
19
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
20
|
+
#
|
21
|
+
|
22
|
+
module ODFWriter
|
23
|
+
|
24
|
+
########################################################################################
|
25
|
+
#
|
26
|
+
# Document: create document from template
|
27
|
+
#
|
28
|
+
########################################################################################
|
29
|
+
class Document
|
30
|
+
include Images
|
31
|
+
|
32
|
+
######################################################################################
|
33
|
+
#
|
34
|
+
# initialize
|
35
|
+
#
|
36
|
+
######################################################################################
|
37
|
+
def initialize(path = nil, zip_stream: nil, &block)
|
38
|
+
|
39
|
+
@template = ODFWriter::Template.new(path, :zip_stream => zip_stream)
|
40
|
+
|
41
|
+
@fields = {}
|
42
|
+
@field_readers = {}
|
43
|
+
|
44
|
+
@texts = {}
|
45
|
+
@text_readers = {}
|
46
|
+
|
47
|
+
@bookmarks = {}
|
48
|
+
@bookmark_readers = {}
|
49
|
+
|
50
|
+
@images = {}
|
51
|
+
@image_readers = {}
|
52
|
+
|
53
|
+
@tables = {}
|
54
|
+
@table_readers = {}
|
55
|
+
|
56
|
+
@sections = {}
|
57
|
+
@section_readers = {}
|
58
|
+
|
59
|
+
@styles = {}
|
60
|
+
@list_styles = {}
|
61
|
+
|
62
|
+
if block_given?
|
63
|
+
instance_eval(&block)
|
64
|
+
end
|
65
|
+
|
66
|
+
end #def
|
67
|
+
|
68
|
+
######################################################################################
|
69
|
+
#
|
70
|
+
# add_readers
|
71
|
+
#
|
72
|
+
######################################################################################
|
73
|
+
def add_readers(files = ODFWriter::Template::CONTENT_FILES.keys)
|
74
|
+
files.each do |file|
|
75
|
+
add_bookmark_reader(file)
|
76
|
+
add_field_reader(file)
|
77
|
+
add_text_reader(file)
|
78
|
+
add_image_reader(file)
|
79
|
+
add_section_reader(file)
|
80
|
+
add_table_reader(file)
|
81
|
+
end
|
82
|
+
end #def
|
83
|
+
|
84
|
+
######################################################################################
|
85
|
+
#
|
86
|
+
# add_field
|
87
|
+
#
|
88
|
+
######################################################################################
|
89
|
+
def add_field(file, name, opts={}, &block)
|
90
|
+
opts.merge!(:name => name)
|
91
|
+
@fields[file] ||= []; @fields[file] << Field.new(opts, &block)
|
92
|
+
end #def
|
93
|
+
|
94
|
+
######################################################################################
|
95
|
+
#
|
96
|
+
# add_field_reader
|
97
|
+
#
|
98
|
+
######################################################################################
|
99
|
+
def add_field_reader(file, name=nil)
|
100
|
+
@field_readers[file] ||= []; @field_readers[file] << FieldReader.new(:name => name)
|
101
|
+
end #def
|
102
|
+
|
103
|
+
######################################################################################
|
104
|
+
#
|
105
|
+
# add_text
|
106
|
+
#
|
107
|
+
######################################################################################
|
108
|
+
def add_text(file, name, opts={}, &block)
|
109
|
+
opts.merge!(:name => name)
|
110
|
+
@texts[file] ||= []; @texts[file] << Text.new(opts, &block)
|
111
|
+
end #def
|
112
|
+
|
113
|
+
######################################################################################
|
114
|
+
#
|
115
|
+
# add_text_reader
|
116
|
+
#
|
117
|
+
######################################################################################
|
118
|
+
def add_text_reader(file, name=nil)
|
119
|
+
@text_readers[file] ||= []; @text_readers[file] << TextReader.new(:name => name)
|
120
|
+
end #def
|
121
|
+
|
122
|
+
######################################################################################
|
123
|
+
#
|
124
|
+
# add_bookmark
|
125
|
+
#
|
126
|
+
######################################################################################
|
127
|
+
def add_bookmark(file, name, opts={}, &block)
|
128
|
+
opts.merge!(:name => name)
|
129
|
+
@bookmarks[file] ||= []; @bookmarks[file] << Bookmark.new(opts, &block)
|
130
|
+
end #def
|
131
|
+
|
132
|
+
######################################################################################
|
133
|
+
#
|
134
|
+
# add_bookmark_reader
|
135
|
+
#
|
136
|
+
######################################################################################
|
137
|
+
def add_bookmark_reader(file, name=nil)
|
138
|
+
@bookmark_readers[file] ||= []; @bookmark_readers[file] << BookmarkReader.new(:name => name)
|
139
|
+
end #def
|
140
|
+
|
141
|
+
######################################################################################
|
142
|
+
#
|
143
|
+
# add_image
|
144
|
+
#
|
145
|
+
######################################################################################
|
146
|
+
def add_image(file, name, opts={}, &block)
|
147
|
+
opts.merge!(:name => name)
|
148
|
+
@images[file] ||= []; @images[file] << Image.new(opts, &block)
|
149
|
+
end #def
|
150
|
+
|
151
|
+
######################################################################################
|
152
|
+
#
|
153
|
+
# add_image_reader
|
154
|
+
#
|
155
|
+
######################################################################################
|
156
|
+
def add_image_reader(file, name=nil)
|
157
|
+
@image_readers[file] ||= []; @image_readers[file] << ImageReader.new(:name => name)
|
158
|
+
end #def
|
159
|
+
|
160
|
+
######################################################################################
|
161
|
+
#
|
162
|
+
# add_table
|
163
|
+
#
|
164
|
+
######################################################################################
|
165
|
+
def add_table(file, name, collection, opts={})
|
166
|
+
opts.merge!(:name => name, :collection => collection)
|
167
|
+
table = Table.new(opts)
|
168
|
+
@tables[file] ||= []; @tables[file] << table
|
169
|
+
yield(table)
|
170
|
+
end #def
|
171
|
+
|
172
|
+
######################################################################################
|
173
|
+
#
|
174
|
+
# add_table_reader
|
175
|
+
#
|
176
|
+
######################################################################################
|
177
|
+
def add_table_reader(file, name=nil)
|
178
|
+
@table_readers[file] ||= []; @table_readers[file] << TableReader.new(:name => name)
|
179
|
+
end #def
|
180
|
+
|
181
|
+
######################################################################################
|
182
|
+
#
|
183
|
+
# add_section
|
184
|
+
#
|
185
|
+
######################################################################################
|
186
|
+
def add_section(file, name, collection, opts={})
|
187
|
+
opts.merge!(:name => name, :collection => collection)
|
188
|
+
section = Section.new(opts)
|
189
|
+
@sections[file] ||= []; @sections[file] << section
|
190
|
+
yield(section)
|
191
|
+
end #def
|
192
|
+
|
193
|
+
######################################################################################
|
194
|
+
#
|
195
|
+
# add_section_reader
|
196
|
+
#
|
197
|
+
######################################################################################
|
198
|
+
def add_section_reader(file, name=nil)
|
199
|
+
@section_readers[file] ||= []; @section_readers[file] << SectionReader.new(:name => name)
|
200
|
+
end #def
|
201
|
+
|
202
|
+
######################################################################################
|
203
|
+
#
|
204
|
+
# add_style
|
205
|
+
#
|
206
|
+
######################################################################################
|
207
|
+
def add_style(root, *styles )
|
208
|
+
@styles[root] ||= []; @styles[root] << Style.new( *styles )
|
209
|
+
end #def
|
210
|
+
|
211
|
+
######################################################################################
|
212
|
+
#
|
213
|
+
# add_list_style
|
214
|
+
#
|
215
|
+
######################################################################################
|
216
|
+
def add_list_style(root, *list_styles )
|
217
|
+
list_styles.each do |list_style|
|
218
|
+
@list_styles[root] ||= []; @list_styles[root] << ListStyle.new( list_style )
|
219
|
+
end
|
220
|
+
end #def
|
221
|
+
|
222
|
+
######################################################################################
|
223
|
+
#
|
224
|
+
# tree
|
225
|
+
#
|
226
|
+
######################################################################################
|
227
|
+
def tree
|
228
|
+
results = {}
|
229
|
+
@template.content do |file, doc|
|
230
|
+
#results.deep_merge!( leafs( file, doc)) # requires Rails
|
231
|
+
results = deep_merge(results, leafs( file, doc))
|
232
|
+
end
|
233
|
+
results
|
234
|
+
end #def
|
235
|
+
|
236
|
+
######################################################################################
|
237
|
+
#
|
238
|
+
# leafs
|
239
|
+
#
|
240
|
+
######################################################################################
|
241
|
+
def leafs( file, doc)
|
242
|
+
results={}
|
243
|
+
# requires Rails
|
244
|
+
# results.deep_merge! @bookmark_readers[file].map { |r| r.paths(file, doc) }.inject{|m,n| m.deep_merge(n){|k, v1,v2| v1 + v2}} if @bookmark_readers[file]
|
245
|
+
# results.deep_merge! @field_readers[file].map { |r| r.paths(file, doc) }.inject{|m,n| m.deep_merge(n){|k, v1,v2| v1 + v2}} if @field_readers[file]
|
246
|
+
# results.deep_merge! @text_readers[file].map { |r| r.paths(file, doc) }.inject{|m,n| m.deep_merge(n){|k, v1,v2| v1 + v2}} if @text_readers[file]
|
247
|
+
# results.deep_merge! @image_readers[file].map { |r| r.paths(file, doc) }.inject{|m,n| m.deep_merge(n){|k, v1,v2| v1 + v2}} if @image_readers[file]
|
248
|
+
|
249
|
+
results = deep_merge( results, @bookmark_readers[file].map { |r| r.paths(file, doc) }.inject{|m,n| deep_merge(m, n)} ) if @bookmark_readers[file]
|
250
|
+
results = deep_merge( results, @field_readers[file].map { |r| r.paths(file, doc) }.inject{|m,n| deep_merge(m, n)} ) if @field_readers[file]
|
251
|
+
results = deep_merge( results, @text_readers[file].map { |r| r.paths(file, doc) }.inject{|m,n| deep_merge(m, n)} ) if @text_readers[file]
|
252
|
+
results = deep_merge( results, @image_readers[file].map { |r| r.paths(file, doc) }.inject{|m,n| deep_merge(m, n)} ) if @image_readers[file]
|
253
|
+
results
|
254
|
+
end #def
|
255
|
+
|
256
|
+
######################################################################################
|
257
|
+
#
|
258
|
+
# populate
|
259
|
+
#
|
260
|
+
######################################################################################
|
261
|
+
def populate(object, options={})
|
262
|
+
|
263
|
+
file = options[:file] || :content
|
264
|
+
coll = options[:coll] || []
|
265
|
+
tree = options[:tree] || self.tree
|
266
|
+
prok = options[:proc]
|
267
|
+
list = options[:list]; list = Array(list).compact
|
268
|
+
|
269
|
+
tree.each do |key, names|
|
270
|
+
case key
|
271
|
+
when :fields
|
272
|
+
names.each do |name|
|
273
|
+
add_field(file, name, :value => prok ? prok.call(object, name) : object.try(name.downcase.to_sym))
|
274
|
+
end #def
|
275
|
+
when :texts
|
276
|
+
names.each do |name|
|
277
|
+
add_text(file, name, :value => prok ? prok.call(object, name) : object.try(name.downcase.to_sym))
|
278
|
+
end #def
|
279
|
+
when :bookmarks
|
280
|
+
names.each do |name|
|
281
|
+
add_bookmark(file, name, :value => prok ? prok.call(object, name) : object.try(name.downcase.to_sym))
|
282
|
+
end #def
|
283
|
+
when :images
|
284
|
+
names.each do |name|
|
285
|
+
add_image(file, name, :value => (prok ? prok.call(object, name) : object.try(name.downcase.to_sym)))
|
286
|
+
end #def
|
287
|
+
when :tables
|
288
|
+
names.each do |name, table_tree|
|
289
|
+
if list.include?(name)
|
290
|
+
add_table(file, name, coll, options){|table| table.populate(table_tree, options)}
|
291
|
+
elsif object.respond_to?(name.underscore.to_sym)
|
292
|
+
add_table(file, name, arrify(object.send(name.underscore.to_sym)), options){|table| table.populate(table_tree, options)}
|
293
|
+
end
|
294
|
+
end #def
|
295
|
+
when :sections
|
296
|
+
names.each do |name, section_tree|
|
297
|
+
if list.include?(name)
|
298
|
+
add_section(file, name, coll, options){|section| section.populate(section_tree, options)} if list.include?(name)
|
299
|
+
elsif object.respond_to?(name.underscore.to_sym)
|
300
|
+
add_section(file, name, arrify(object.send(name.underscore.to_sym)), options){|section| section.populate(section_tree, options)}
|
301
|
+
end
|
302
|
+
end #def
|
303
|
+
when :files
|
304
|
+
names.each do |file, file_tree|
|
305
|
+
populate(object, options.merge(:file => file, :tree => file_tree))
|
306
|
+
end
|
307
|
+
end #case
|
308
|
+
end #each
|
309
|
+
end #def
|
310
|
+
|
311
|
+
######################################################################################
|
312
|
+
#
|
313
|
+
# write
|
314
|
+
#
|
315
|
+
######################################################################################
|
316
|
+
def write(dest = nil)
|
317
|
+
|
318
|
+
@template.update_content do |template|
|
319
|
+
|
320
|
+
template.update_files do |file, doc, manifest|
|
321
|
+
|
322
|
+
@styles[file].to_a.each { |s| s.add_style(doc) }
|
323
|
+
@list_styles[file].to_a.each { |s| s.add_list_style(doc) }
|
324
|
+
|
325
|
+
@sections[file].to_a.each { |s| s.replace!(doc, manifest, template) }
|
326
|
+
@tables[file].to_a.each { |t| t.replace!(doc, manifest, template) }
|
327
|
+
|
328
|
+
@texts[file].to_a.each { |t| t.replace!(doc) }
|
329
|
+
@fields[file].to_a.each { |f| f.replace!(doc) }
|
330
|
+
|
331
|
+
@bookmarks[file].to_a.each { |b| b.replace!(doc) }
|
332
|
+
@images[file].to_a.each { |i| i.replace!(doc, manifest, template) }
|
333
|
+
|
334
|
+
Image.unique_image_names( doc ) if @images.present?
|
335
|
+
end
|
336
|
+
|
337
|
+
end
|
338
|
+
|
339
|
+
if dest
|
340
|
+
::File.open(dest, "wb") {|f| f.write(@template.data) }
|
341
|
+
else
|
342
|
+
@template.data
|
343
|
+
end
|
344
|
+
|
345
|
+
end #def
|
346
|
+
|
347
|
+
######################################################################################
|
348
|
+
#
|
349
|
+
# private
|
350
|
+
#
|
351
|
+
######################################################################################
|
352
|
+
private
|
353
|
+
|
354
|
+
# deep_merge without using Rails
|
355
|
+
def deep_merge(left, right)
|
356
|
+
merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : [:undefined, nil, :nil].include?(v2) ? v1 : v1 + v2 }
|
357
|
+
left.merge(right, &merger)
|
358
|
+
end #def
|
359
|
+
|
360
|
+
def arrify(obj)
|
361
|
+
case obj
|
362
|
+
when Array
|
363
|
+
obj
|
364
|
+
when Hash
|
365
|
+
[obj]
|
366
|
+
else
|
367
|
+
obj.respond_to?(:to_a) ? obj.to_a : [obj]
|
368
|
+
end
|
369
|
+
end #def
|
370
|
+
|
371
|
+
end #class
|
372
|
+
end #module
|
@@ -0,0 +1,174 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# Ruby Gem to create a self populating Open Document Format (.odf) text file.
|
4
|
+
#
|
5
|
+
# Copyright 2021 Stephan Wenzel <stephan.wenzel@drwpatent.de>
|
6
|
+
#
|
7
|
+
# This program is free software; you can redistribute it and/or
|
8
|
+
# modify it under the terms of the GNU General Public License
|
9
|
+
# as published by the Free Software Foundation; either version 2
|
10
|
+
# of the License, or (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with this program; if not, write to the Free Software
|
19
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
20
|
+
#
|
21
|
+
|
22
|
+
module ODFWriter
|
23
|
+
|
24
|
+
########################################################################################
|
25
|
+
#
|
26
|
+
# Field: replace fields
|
27
|
+
#
|
28
|
+
########################################################################################
|
29
|
+
class Field
|
30
|
+
|
31
|
+
######################################################################################
|
32
|
+
#
|
33
|
+
# constants
|
34
|
+
#
|
35
|
+
######################################################################################
|
36
|
+
DELIMITERS = %w([ ])
|
37
|
+
|
38
|
+
######################################################################################
|
39
|
+
#
|
40
|
+
# constants
|
41
|
+
#
|
42
|
+
######################################################################################
|
43
|
+
attr_accessor :name
|
44
|
+
|
45
|
+
######################################################################################
|
46
|
+
#
|
47
|
+
# initialize
|
48
|
+
#
|
49
|
+
######################################################################################
|
50
|
+
def initialize(options, &block)
|
51
|
+
|
52
|
+
@name = options[:name]
|
53
|
+
@value = options[:value]
|
54
|
+
@field = options[:field]
|
55
|
+
@key = @field || @name
|
56
|
+
@proc = options[:proc]
|
57
|
+
|
58
|
+
@remove_classes = options[:remove_classes]
|
59
|
+
@remove_class_prefix = options[:remove_class_prefix]
|
60
|
+
@remove_class_suffix = options[:remove_class_suffix]
|
61
|
+
|
62
|
+
@value ||= @proc
|
63
|
+
|
64
|
+
unless @value
|
65
|
+
if block_given?
|
66
|
+
@value = block
|
67
|
+
else
|
68
|
+
@value = lambda { |item, key| field(item, key) }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end #def
|
72
|
+
|
73
|
+
######################################################################################
|
74
|
+
#
|
75
|
+
# replace!
|
76
|
+
#
|
77
|
+
######################################################################################
|
78
|
+
def replace!(content, item = nil)
|
79
|
+
txt = content.inner_html
|
80
|
+
txt.gsub!(placeholder, sanitize(value(item)))
|
81
|
+
content.inner_html = txt
|
82
|
+
end #def
|
83
|
+
|
84
|
+
######################################################################################
|
85
|
+
#
|
86
|
+
# value
|
87
|
+
#
|
88
|
+
######################################################################################
|
89
|
+
def value(item = nil)
|
90
|
+
@value.is_a?(Proc) ? @value.call(item, @key) : @value
|
91
|
+
end #def
|
92
|
+
|
93
|
+
######################################################################################
|
94
|
+
#
|
95
|
+
# field
|
96
|
+
#
|
97
|
+
######################################################################################
|
98
|
+
def field(item, key)
|
99
|
+
case item
|
100
|
+
when NilClass
|
101
|
+
key
|
102
|
+
when Hash
|
103
|
+
hash_value(item, key)
|
104
|
+
else
|
105
|
+
item_field(item, key)
|
106
|
+
end
|
107
|
+
end #def
|
108
|
+
|
109
|
+
######################################################################################
|
110
|
+
#
|
111
|
+
# private
|
112
|
+
#
|
113
|
+
######################################################################################
|
114
|
+
private
|
115
|
+
|
116
|
+
######################################################################################
|
117
|
+
# hash_value
|
118
|
+
######################################################################################
|
119
|
+
def hash_value(hash, key)
|
120
|
+
hash[key.to_s] || hash[key.to_sym] ||
|
121
|
+
hash[key.to_s.underscore] || hash[key.to_s.underscore.to_sym]
|
122
|
+
end #def
|
123
|
+
|
124
|
+
######################################################################################
|
125
|
+
# item_field
|
126
|
+
######################################################################################
|
127
|
+
def item_field(item, field)
|
128
|
+
item.try(field.to_s.to_sym) ||
|
129
|
+
item.try(field.to_s.underscore.to_sym)
|
130
|
+
end #def
|
131
|
+
|
132
|
+
######################################################################################
|
133
|
+
# placeholder
|
134
|
+
######################################################################################
|
135
|
+
def placeholder
|
136
|
+
"#{DELIMITERS[0]}#{@name.to_s.upcase}#{DELIMITERS[1]}"
|
137
|
+
end #def
|
138
|
+
|
139
|
+
######################################################################################
|
140
|
+
# sanitize
|
141
|
+
######################################################################################
|
142
|
+
def sanitize(text)
|
143
|
+
# if we get some object, which is not a string, Numeric or the like
|
144
|
+
# f.i. a Hash or an Arry or a CollectionProxy or an image then return @key to avoid
|
145
|
+
# uggly errors
|
146
|
+
return @key.to_s if text.respond_to?(:each)
|
147
|
+
text = html_escape(text)
|
148
|
+
text = odf_linebreak(text)
|
149
|
+
text
|
150
|
+
end #def
|
151
|
+
|
152
|
+
HTML_ESCAPE = { '&' => '&', '>' => '>', '<' => '<', '"' => '"' }
|
153
|
+
|
154
|
+
def html_escape(s)
|
155
|
+
return "" unless s
|
156
|
+
s.to_s.gsub(/[&"><]/) { |special| HTML_ESCAPE[special] }
|
157
|
+
end #def
|
158
|
+
|
159
|
+
def odf_linebreak(s)
|
160
|
+
return "" unless s
|
161
|
+
s = s.encode(universal_newline: true)
|
162
|
+
s.to_s.gsub("\n", "<text:line-break/>").gsub("<br.*?>", "<text:line-break/>")
|
163
|
+
end #def
|
164
|
+
|
165
|
+
def deep_fields(fs)
|
166
|
+
fs.split(/\./)
|
167
|
+
end #def
|
168
|
+
|
169
|
+
def deep_try(item, f)
|
170
|
+
deep_fields(f).inject(item) {|obj,f| obj.try(f.to_s.underscore.to_sym)}
|
171
|
+
end #def
|
172
|
+
|
173
|
+
end #class
|
174
|
+
end #module
|