pslm 0.0.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: fcfdfd901e4bdd0796aa7d85ca0037cb8c0b2e1e
4
+ data.tar.gz: 99ab169ac0873ce40653ebfb91f1a599f3fd1775
5
+ SHA512:
6
+ metadata.gz: 141897655cd0db39adb3b32822cbd2ac9f77884e383297bfa1d7caf06c1cf11b1ac51452d6292fbfc5e15f424bfcdf5d3d53a5ccc71f74af6bd57ad017947899
7
+ data.tar.gz: 3c777f32f4dc5f914afcc0cf57799dff9b82f00963f2abf8f489cbf73af0de0f2943211626a1b13add3354e74c3ca0780a14bdea7f594d8896be146a0204abb9
@@ -0,0 +1,150 @@
1
+ #!/usr/bin/env/ruby
2
+ # -*- coding: utf-8 -*-
3
+ # pslm - psalm processing utility
4
+
5
+ require 'pslm'
6
+ require 'optparse'
7
+
8
+ require 'pslm/structuredsetup'
9
+
10
+ DEFAULT_SETUP = {
11
+ :general => {
12
+ :format => 'latex', # latex|pslm
13
+ },
14
+ :input => {
15
+ :has_title => true,
16
+ :title => nil, # to overwrite the title loaded from the input file
17
+ :join => false,
18
+ },
19
+ :output => Pslm::Outputter::DEFAULT_SETUP.dup
20
+ }
21
+
22
+ setup = StructuredSetup.new DEFAULT_SETUP
23
+ [:accents, :preparatory].each do |o|
24
+ setup[:output][:pointing].delete o
25
+ end
26
+
27
+ # TODO the setup below doesn't yet respect the structure of the options above
28
+ # TODO many of the options aren't implemented yet, some will never be
29
+ optparse = OptionParser.new do |opts|
30
+
31
+ opts.separator "== General options"
32
+
33
+ opts.on "-o", "--output FILE", "Save output to given path." do |out|
34
+ setup[:general][:output_file] = out
35
+ end
36
+
37
+ opts.on "-f", "--format F", "Select output format." do |f|
38
+ setup[:general][:format] = f
39
+ end
40
+
41
+ opts.separator "== Input interpretation"
42
+
43
+ opts.on "--no-title", "Don't consider the first line to contain a psalm title" do
44
+ setup[:input][:has_title] = false
45
+ end
46
+ opts.on "--set-title TITLE", "Manually set title" do |t|
47
+ setup[:input][:title] = t
48
+ end
49
+ opts.on "--append TEXT", "Text to be appended at the end (before processing)." do |t|
50
+ setup[:input][:append] = t
51
+ end
52
+ opts.on "-j", "--join", "Join all given input files" do
53
+ setup[:input][:join] = true
54
+ end
55
+
56
+ opts.separator "== Output formatting"
57
+
58
+ opts.on "--skip-title", "Don't set the title" do
59
+ setup[:output][:title][:template] = :no
60
+ end
61
+ opts.on "--title-template [TEMPLATE]", "Use a specified template instead of the default one." do |p|
62
+ setup[:output][:title][:template] = p
63
+ end
64
+ opts.on "-k", "--skip-verses NUM", Integer, "Skip initial verses" do |i|
65
+ setup[:output][:skip_verses] = i
66
+ end
67
+
68
+ opts.on "-a", "--accents NUMS", "a:b - Numbers of accents to be pointed in each half-verse" do |str|
69
+ a1, a2 = str.split ':'
70
+ if a1 && a1 != "" then
71
+ setup.get_dv(:output, :pointing, :accents, [])[0] = a1.to_i
72
+ end
73
+ if a2 && a2 != "" then
74
+ setup.get_dv(:output, :pointing, :accents, [])[1] = a2.to_i
75
+ end
76
+ end
77
+ # TODO merge with the previous option to a1[,p1]:a2[,p2]
78
+ opts.on "-p", "--preparatory-syllables NUMS", "a:b - How many preparatory syllables in each half-verse" do |str|
79
+ a1, a2 = str.split ':'
80
+ if a1 && a1 != "" then
81
+ setup.get_dv(:output, :pointing, :preparatory, [])[0] = a1.to_i
82
+ end
83
+ if a2 && a2 != "" then
84
+ setup.get_dv(:output, :pointing, :preparatory, [])[1] = a2.to_i
85
+ end
86
+ end
87
+ opts.on "-t", "--tone TONE", "point accents and preparatory syllables for a given psalm tone (like I.f or VIII.G)" do |str|
88
+ setup[:output][:pointing][:tone] = str
89
+ end
90
+
91
+ opts.on "-s", "--accents-style SYM", "underline (default) | bold" do |s|
92
+ sym = s.to_sym
93
+ setup[:output][:pointing][:accent_style] = sym
94
+ end
95
+ # Needs LaTeX package lettrine!
96
+ # TODO
97
+ opts.on "--lettrine", "Large first character of the psalm." do
98
+ setup[:output][:lettrine] = {}
99
+ end
100
+ opts.on "--split-verses", "Each verse part on it's own line" do
101
+ setup[:output][:parts][:novydvur_newlines] = true # like in the psalter of the Novy Dvur Trappist abbey
102
+ end
103
+ # TODO
104
+ opts.on "--pretitle TEXT", "Text to be printed as beginning of the title." do |t|
105
+ setup[:output][:prepend_text] = t
106
+ end
107
+ opts.on "--output-append TEXT", "Text to be appended at the end (of the last line after processing)." do |t|
108
+ setup[:output][:final_add_content] = {:append => t}
109
+ end
110
+ # This is useful when we want to append a doxology after the psalm
111
+ # as a separate paragraph
112
+ # TODO
113
+ opts.on "--linebreak-at-the-end", "Make a line-break after the last line" do
114
+ setup[:output][:line_break_last_line] = true
115
+ end
116
+ opts.on "--dashes", "Dash at the end of each psalm paragraph" do
117
+ setup[:output][:strophes][:end_marks] = :semantic
118
+ end
119
+ # TODO
120
+ opts.on "--no-paragraph", "No empty line after each psalm paragraph." do
121
+ setup[:output][:paragraph_space] = false
122
+ end
123
+ opts.on "--guillemets", "Convert american quotes to french ones (guillemets)." do
124
+ setup[:output][:quote] = :guillemets
125
+ end
126
+ # TODO
127
+ opts.on "-m", "--mark-short-verses", "Insert warning marks in verses that are too short" do
128
+ setup[:output][:mark_short_verses] = true
129
+ end
130
+ opts.on "--wrapper NAME", "Wrap output in a wrapper with the given name" do |n|
131
+ setup[:output][:wrapper][:environment_name] = n
132
+ end
133
+ end
134
+
135
+ optparse.parse!
136
+
137
+ # use default pointing setup if necessary
138
+ unless setup[:output][:pointing].has_key? :tone
139
+ [:accents, :preparatory].each do |o|
140
+ unless setup[:output][:pointing].has_key? o
141
+ setup[:output][:pointing][o] = DEFAULT_SETUP[:output][:pointing][o].dup
142
+ end
143
+ end
144
+ end
145
+
146
+ if ARGV.empty? then
147
+ raise "Program expects filenames as arguments."
148
+ end
149
+
150
+ Pslm::PsalmPointer.new(setup).process(ARGV, setup[:general][:output_file])
@@ -0,0 +1,17 @@
1
+ # main file of the pslm library
2
+
3
+ module Pslm
4
+ end
5
+
6
+ require_relative 'pslm/pslmreader'
7
+ require_relative 'pslm/psalm'
8
+ require_relative 'pslm/psalmpointer'
9
+ require_relative 'pslm/psalmpatterns'
10
+
11
+ require_relative 'pslm/outputter'
12
+ require_relative 'pslm/latexoutputter'
13
+ require_relative 'pslm/pslmoutputter'
14
+ require_relative 'pslm/consoleoutputter'
15
+
16
+ require_relative 'pslm/structuredsetup'
17
+ require_relative 'pslm/joinedinput'
@@ -0,0 +1,281 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'colorize'
4
+
5
+ module Pslm
6
+
7
+ # formats a psalm for console output
8
+ class ConsoleOutputter < Outputter
9
+
10
+ FORMATTER_ORDER = [
11
+ :pointing,
12
+ :parts,
13
+ :verses,
14
+ :skip_verses,
15
+ :title,
16
+ :strophes,
17
+ :prepend_text,
18
+ :output_append_text,
19
+ :line_break_last_line,
20
+ :mark_short_verses
21
+ ]
22
+
23
+ # takes a Psalm, returns a String with the psalm formatted
24
+ def process_psalm(psalm, opts={})
25
+ formatters = get_formatters(opts)
26
+
27
+ # build the output; on each step apply the appropriate method
28
+ # of each formatter in the given order
29
+ psalm_assembled = psalm.verses.collect do |verse|
30
+ process_verse(verse, opts, psalm, formatters)
31
+ end.delete_if {|v| v == '' }.join "\n"
32
+
33
+ return Formatter.format(formatters, :psalm,
34
+ psalm_assembled,
35
+ psalm)
36
+ end
37
+
38
+ alias :process :process_psalm
39
+
40
+ def process_verse(verse, opts, psalm=nil, formatters=nil)
41
+ formatters = formatters || get_formatters(opts)
42
+
43
+ verse_assembled = verse.parts.collect do |part|
44
+
45
+ part_assembled = part.words.reverse.collect do |word|
46
+
47
+ word_assembled = word.syllables.reverse.collect do |syll|
48
+ Formatter.format(formatters, :syllable,
49
+ syll, part, word, syll)
50
+ end.reverse.join ''
51
+
52
+ Formatter.format(formatters, :word,
53
+ word_assembled, word)
54
+ end.reverse.join ' '
55
+
56
+ Formatter.format(formatters, :part,
57
+ part_assembled, part)
58
+ end.join ''
59
+
60
+ return Formatter.format(formatters, :verse,
61
+ verse_assembled, psalm, verse)
62
+ end
63
+
64
+ # takes a Hash of options,
65
+ # returns a list of accordingly initialized Formatter instances
66
+ def get_formatters(options)
67
+ return FORMATTER_ORDER.collect do |f|
68
+ next unless options.include? f
69
+
70
+ get_formatter(f, options[f])
71
+ end.compact!
72
+ end
73
+
74
+ # takes a Symbol - name of a configuration option, and option/s value;
75
+ # returns an instance of a corresponding Formatter class or nil
76
+ def get_formatter(sym, options)
77
+ cls_name = sym.to_s.gsub(/_(\w)/) {|m| m[1].upcase }
78
+ cls_name[0] = cls_name[0].upcase
79
+ cls_name += 'Formatter'
80
+
81
+ if self.class.const_defined? cls_name then
82
+ return self.class.const_get(cls_name).new(options)
83
+ else
84
+ return nil
85
+ end
86
+ end
87
+
88
+ # abstract superclass of the formatters providing dumb implementation
89
+ # of all formatting methods
90
+ class Formatter
91
+
92
+ class << self
93
+ # lets all the :formatters: subsequently format :text: assembled from :obj: on the assembly :level:
94
+ def format(formatters, level, text, *args)
95
+ formatters.each do |f|
96
+ text = f.send("#{level}_format", text, *args)
97
+ end
98
+ return text
99
+ end
100
+ end
101
+
102
+ def initialize(options)
103
+ @options = options
104
+ @syll_counter = 0
105
+ @word_counter = 0
106
+ @part_counter = 0
107
+ @verse_counter = 0
108
+ end
109
+
110
+ def psalm_format(text, psalm)
111
+ @syll_counter = 0
112
+ @word_counter = 0
113
+ @part_counter = 0
114
+ @verse_counter = 0
115
+ text
116
+ end
117
+
118
+ def verse_format(text, psalm, verse)
119
+ @verse_counter += 1
120
+ @syll_counter = 0
121
+ @word_counter = 0
122
+ @part_counter = 0
123
+ text
124
+ end
125
+
126
+ def part_format(text, part)
127
+ @part_counter += 1
128
+ @syll_counter = 0
129
+ @word_counter = 0
130
+ text
131
+ end
132
+
133
+ def word_format(text, word)
134
+ @word_counter += 1
135
+ text
136
+ end
137
+
138
+ def syllable_format(text, part, word, syll)
139
+ @syll_counter += 1
140
+ text
141
+ end
142
+ end
143
+
144
+ # marks accentuated and preparatory syllables
145
+ class PointingFormatter < Formatter
146
+ def initialize(options)
147
+ super(options)
148
+ @accent_counter = 0
149
+ @preparatories_counter = 0
150
+
151
+ # validate options
152
+ if @options.has_key? :tone and
153
+ (@options.has_key? :accents or @options.has_key? :preparatory) then
154
+ raise RuntimeError.new('Overconfigured: both accents/preparatories number and psalm tone specified.')
155
+ elsif @options.has_key? :accents then
156
+ # ok, nothing to do
157
+ elsif @options.has_key? :tone
158
+ # convert psalm tone identifier to numbers
159
+ tone = PsalmPatterns.default.tone_data_str(@options[:tone])
160
+ @options[:accents] = tone.collect {|part| part[0] }
161
+ @options[:preparatory] = tone.collect {|part| part[1] }
162
+ end
163
+
164
+ if @options[:accent_style] != nil then
165
+ if MARKS.has_key? @options[:accent_style] then
166
+ @accent_style = MARKS[@options[:accent_style]]
167
+ else
168
+ # user_defined style
169
+ @accent_style = @options[:accent_style].to_sym
170
+ end
171
+ else
172
+ @accent_style = :blue
173
+ end
174
+
175
+ @preparatory_style = :magenta
176
+ end
177
+
178
+ def part_format(text, part)
179
+ super(text, part)
180
+ @accent_counter = 0
181
+ @preparatories_counter = 0
182
+ text
183
+ end
184
+
185
+ MARKS = {
186
+ :underline => {:color => :blue, :mode => :underline},
187
+ :bold => {:color => :blue, :mode => :bold},
188
+ :semantic => {:color => :blue, :mode => :bold}
189
+ }
190
+
191
+ def syllable_format(text, part, word, syll)
192
+ super(text, part, word, syll)
193
+ r = text
194
+ if syll.accent? then
195
+ @accent_counter += 1
196
+ if @accent_counter <= num_accents_for(part) then
197
+ r = r.colorize @accent_style
198
+ end
199
+ end
200
+
201
+
202
+ if num_preparatory_syllables_for(part) > 0 and
203
+ @accent_counter >= num_accents_for(part) then
204
+
205
+ if @preparatories_counter >= 1 and
206
+ @preparatories_counter <= num_preparatory_syllables_for(part) then
207
+ r = r.colorize @preparatory_style
208
+ end
209
+
210
+ @preparatories_counter += 1
211
+ end
212
+
213
+ return r
214
+ end
215
+
216
+ private
217
+
218
+ # how many accents to mark in this verse-part?
219
+ def num_accents_for(part)
220
+ case part.pos
221
+ when :flex
222
+ 1
223
+ when :first
224
+ @options[:accents][0]
225
+ when :second
226
+ @options[:accents][1]
227
+ end
228
+ end
229
+
230
+ # how many preparatory syllables to mark in this verse-part?
231
+ def num_preparatory_syllables_for(part)
232
+ case part.pos
233
+ when :flex
234
+ 0
235
+ when :first
236
+ @options[:preparatory][0]
237
+ when :second
238
+ @options[:preparatory][1]
239
+ end
240
+ end
241
+ end
242
+
243
+ # formatting of verse parts -
244
+ # adds part dividing marks (flex, asterisk),
245
+ # eventually inserts newlines
246
+ class PartsFormatter < Formatter
247
+
248
+ MARKS = { :flex => ' + ', :first => ' * ', :second => ' ' }
249
+
250
+ def part_format(text, part)
251
+ text + MARKS[part.pos].colorize(:color => :light_blue) +
252
+ ((@options[:novydvur_newlines] && part.pos != :second) ? "\n" : '')
253
+ end
254
+ end
255
+
256
+ # skips verses at the beginning
257
+ class SkipVersesFormatter < Formatter
258
+ def initialize(options)
259
+ super(options)
260
+ @skip_verses = @options # takes just one number as a parameter
261
+ end
262
+
263
+ def verse_format(text, psalm, verse)
264
+ #super(text, psalm, verse)
265
+ @verse_counter += 1
266
+ if @verse_counter <= @skip_verses then
267
+ return ""
268
+ end
269
+
270
+ return text
271
+ end
272
+ end
273
+
274
+ # formats title
275
+ class TitleFormatter < Formatter
276
+ def psalm_format(text, psalm)
277
+ psalm.header.title.colorize(:mode => :bold) + "\n\n" + text
278
+ end
279
+ end
280
+ end
281
+ end