legal_markdown 0.1.5 → 0.2.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.
@@ -1,60 +1,55 @@
1
1
  #! ruby
2
2
  require 'yaml'
3
- require 'English'
4
- require 'roman-numerals'
5
- require "legal_markdown/version"
6
-
7
- module LegalMarkdown
8
- extend self
9
-
10
- def markdown_to_legal(*args)
11
- # Get the Content & Yaml Data
12
- data = load(*args)
13
- parsed_content = parse_file(data[0])
14
- # Run the Mixins
15
- mixed_content = mixing_in(parsed_content[0], parsed_content[1])
16
- # Run the Pandoc Title Block
17
- pandoc_content = pandoc_title_block( mixed_content[1] ) + mixed_content[0]
18
- # Run the Headers
19
- headed_content = headers_on(mixed_content[1], pandoc_content)
20
- # Write the file
21
- file = write_it( @filename, headed_content )
3
+ require File.dirname(__FILE__) + '/legal_markdown/roman-numerals'
4
+ require File.dirname(__FILE__) + '/legal_markdown/version'
5
+ require File.dirname(__FILE__) + '/legal_markdown/make_yaml_frontmatter.rb'
6
+
7
+ class LegalToMarkdown
8
+
9
+ def self.main(*args)
10
+ if(!ARGV[0])
11
+ STDERR.puts "Sorry, I didn't understand that. Please give me your legal_markdown filenames or \"-\" for stdin."
12
+ exit 0
13
+ elsif ARGV.include?("--headers")
14
+ MakeYamlFrontMatter.new(ARGV)
15
+ else
16
+ LegalToMarkdown.new(ARGV)
17
+ end
18
+ end # main
19
+
20
+ def initialize(*args)
21
+ data = load(*args) # Get the Content
22
+ parsed_content = parse_file(data) # Load the YAML front matter
23
+ mixed_content = mixing_in(parsed_content[0], parsed_content[1]) # Run the Mixins
24
+ headed_content = headers_on(mixed_content[0], mixed_content[1]) # Run the Headers
25
+ file = write_it( headed_content ) # Write the file
22
26
  end
23
27
 
24
28
  private
25
29
  # ----------------------
26
30
  # | Step 1 |
27
31
  # ----------------------
28
- # Parse Options & Load File
32
+ # Parse Options & Load File
29
33
  def load(*args)
30
-
31
- # OPTIONS
32
- # OPTS = {}
33
- # op = OptionParser.new do |x|
34
- # x.banner = 'cat <options> <file>'
35
- # x.separator ''
36
-
37
- # x.on("-A", "--show-all", "Equivalent to -vET")
38
- # { OPTS[:showall] = true }
39
-
40
- # x.on("-b", "--number-nonblank", "number nonempty output lines")
41
- # { OPTS[:number_nonblank] = true }
42
-
43
- # x.on("-x", "--start-from NUM", Integer, "Start numbering from NUM")
44
- # { |n| OPTS[:start_num] = n }
45
-
46
- # x.on("-h", "--help", "Show this message")
47
- # { puts op; exit }
48
- # end
49
- # op.parse!(ARGV)
50
-
51
- # # Example code for dealing with multiple filenames -- but don't think we want to do this.
52
- # ARGV.each{ |fn| output_file(OPTS, fn) }
53
-
54
- # Load Source File
55
- @filename = ARGV[-1]
56
- source_file = File::read(@filename) if File::exists?(@filename) && File::readable?(@filename)
57
- return [source_file, '']
34
+ @output_file = ARGV[-1]
35
+ @input_file = ARGV[-2] ? ARGV[-2] : ARGV[-1]
36
+ begin
37
+ if @output_file != "-" && @input_file != "-"
38
+ source_file = File::read(@input_file) if File::exists?(@input_file) && File::readable?(@input_file)
39
+ elsif @input_file == "-"
40
+ source_file = STDIN.read
41
+ end
42
+ source_file.scan(/(@include (.+)$)/).each do |set|
43
+ partial_file = set[1]
44
+ to_replace = set[0]
45
+ partial_contents = File::read(partial_file) if File::exists?(partial_file) && File::readable?(partial_file)
46
+ source_file.gsub!(to_replace, partial_contents)
47
+ end
48
+ return source_file
49
+ rescue => e
50
+ puts "Sorry, I could not read the input file #{@input_file}: #{e.message}."
51
+ exit 0
52
+ end
58
53
  end
59
54
 
60
55
  # ----------------------
@@ -65,17 +60,18 @@ module LegalMarkdown
65
60
  def parse_file(source)
66
61
  begin
67
62
  yaml_pattern = /\A(---\s*\n.*?\n?)^(---\s*$\n?)/m
68
- if source =~ yaml_pattern
69
- data = YAML.load($1)
70
- content = $POSTMATCH
63
+ parts = source.partition( yaml_pattern )
64
+ if parts[1] != ""
65
+ headers = YAML.load(parts[1])
66
+ content = parts[2]
71
67
  else
72
- data = {}
68
+ headers = {}
73
69
  content = source
74
70
  end
75
- rescue => e
76
- puts "Error reading file #{File.join(ARGV[0])}: #{e.message}"
71
+ rescue => e
72
+ puts "Sorry, something went wrong when I was loading the YAML front matter: #{e.message}."
77
73
  end
78
- return [data, content]
74
+ return [headers, content]
79
75
  end
80
76
 
81
77
  # ----------------------
@@ -88,20 +84,20 @@ module LegalMarkdown
88
84
  def clauses_mixins( mixins, content )
89
85
  clauses_to_delete = []
90
86
  clauses_to_mixin = []
91
-
87
+
92
88
  mixins.each do | mixin, replacer |
93
89
  replacer = replacer.to_s.downcase
94
90
  clauses_to_delete << mixin if replacer == "false"
95
91
  clauses_to_mixin << mixin if replacer == "true"
96
92
  end
97
-
93
+
98
94
  clauses_to_delete.each { |m| mixins.delete(m) }
99
95
  clauses_to_mixin.each { |m| mixins.delete(m) }
100
96
 
101
97
  until clauses_to_delete.size == 0
102
98
  clauses_to_delete.each do | mixin |
103
- pattern = /(\[{{#{mixin}}}\s*)(.*?\n?)(\])/m
104
- sub_pattern = /\[{{(\S+)}}/m
99
+ pattern = /(\[{{#{mixin}}}\s*?)(.*?\n*?)(\])/m
100
+ sub_pattern = /\[{{(\S+?)}}\s*?/
105
101
  content[pattern]
106
102
  get_it_all = $& || ""
107
103
  sub_clause = $2 || ""
@@ -113,8 +109,8 @@ module LegalMarkdown
113
109
 
114
110
  until clauses_to_mixin.size == 0
115
111
  clauses_to_mixin.each do | mixin |
116
- pattern = /(\[{{#{mixin}}}\s*)(.*?\n?)(\])/m
117
- sub_pattern = /(\[{{\S+}})/m
112
+ pattern = /(\[{{#{mixin}}}\s*?)(.*?\n*?)(\])/m
113
+ sub_pattern = /\[{{(\S+?)}}\s*?/
118
114
  content[pattern]
119
115
  get_it_all = $& || ""
120
116
  sub_clause = $2 || ""
@@ -124,297 +120,297 @@ module LegalMarkdown
124
120
  end
125
121
  end
126
122
 
127
- return [content, mixins]
123
+ return [ mixins, content ]
128
124
  end
129
125
 
130
- def normal_mixins( mixins, content )
126
+ def text_mixins( mixins, content )
131
127
  mixins.each do | mixin, replacer |
132
128
  unless mixin =~ /level-\d/ or mixin =~ /no-reset/ or mixin =~ /no-indent/
133
129
  replacer = replacer.to_s
134
- safe_words = [ "title", "author", "date" ]
135
- pattern = /({{#{mixin}}})/
136
- if content =~ pattern
137
- content = content.gsub( $1, replacer )
138
- mixins.delete( mixin ) unless safe_words.any?{ |s| s.casecmp(mixin) == 0 }
139
- end
130
+ mixin_pattern = /({{#{mixin}}})/
131
+ content = content.gsub( $1, replacer ) if content =~ mixin_pattern
132
+ mixins.delete( mixin )
140
133
  end
141
134
  end
142
- return [content, mixins]
135
+ return [ mixins, content ]
143
136
  end
144
137
 
145
138
  clauses_mixed = clauses_mixins( mixins, content )
146
- mixed = normal_mixins( clauses_mixed[1], clauses_mixed[0] )
147
- return [ mixed[0], mixed[1] ]
139
+ fully_mixed = text_mixins( clauses_mixed[0], clauses_mixed[1] )
140
+ fully_mixed[1].gsub!(/(\n\n+)/, "\n\n")
141
+ return [ fully_mixed[0], fully_mixed[1] ]
148
142
  end
149
143
 
150
144
  # ----------------------
151
145
  # | Step 4 |
152
146
  # ----------------------
153
- # Special YAML fields
154
-
155
- def pandoc_title_block( headers )
156
- title_block = ""
157
- headers.each do | header |
158
- if header[0].casecmp("title") == 0
159
- title_block << "% " + header[1] + "\n"
160
- headers.delete( header )
161
- elsif header[0].casecmp("author") == 0
162
- title_block << "% " + header[1] + "\n"
163
- headers.delete( header )
164
- elsif header[0].casecmp("date") == 0
165
- title_block << "% " + header[1] + "\n\n"
166
- headers.delete( header )
167
- end
168
- end
169
- return title_block
170
- end
171
-
172
- # ----------------------
173
- # | Step 5 |
174
- # ----------------------
175
147
  # Headers
176
148
 
177
149
  def headers_on( headers, content )
178
150
 
151
+ def set_the_subs_arrays( value )
152
+ # takes a core value from the hash pulled from the yaml
153
+ # returns an array with a type symbol and a precursor string
154
+ if value =~ /([IVXLCDM]+)\.\z/ # type1 : {{ I. }}
155
+ return[:type1, value.delete($1 + "."), "", $1, "."]
156
+ elsif value =~ /\(([IVXLCDM]+)\)\z/ # type2 : {{ (I) }}
157
+ return[:type2, value.delete("(" + $1 + ")"), "(", $1, ")"]
158
+ elsif value =~ /([ivxlcdm]+)\.\z/ # type3 : {{ i. }}
159
+ return[:type3, value.delete($1 + "."), "", $1, "."]
160
+ elsif value =~ /\(([ivxlcdm]+)\)\z/ # type4 : {{ (i) }}
161
+ return[:type4, value.delete("(" + $1 + ")"), "(", $1, ")"]
162
+ elsif value =~ /([A-Z]+)\.\z/ # type5 : {{ A. }}
163
+ return[:type5, value.delete($1 + "."), "", $1, "."]
164
+ elsif value =~ /\(([A-Z]+)\)\z/ # type6 : {{ (A) }}
165
+ return[:type6, value.delete("(" + $1 + ")"), "(", $1, ")"]
166
+ elsif value =~ /([a-z]+)\.\z/ # type7 : {{ a. }}
167
+ return[:type7, value.delete($1 + "."), "", $1, "."]
168
+ elsif value =~ /\(([a-z]+)\)\z/ # type8 : {{ (a) }}
169
+ return[:type8, value.delete("(" + $1 + ")"), "(", $1, ")"]
170
+ elsif value =~ /\((\d+)\)\z/ # type9 : {{ (1) }}
171
+ return[:type9, value.delete("(" + $1 + ")"), "(", $1, ")"]
172
+ else value =~ /(\d+)\.\z/ # type0 : {{ 1. }} ... also default
173
+ return[:type0, value.delete($1 + "."), "", $1, "."]
174
+ end
175
+ end
176
+
179
177
  def get_the_substitutions( headers )
180
- # find the headers in the remaining YAML
178
+ # find the headers in the remaining YAML
181
179
  # parse out the headers into level-X and pre-X headers
182
180
  # then combine them into a coherent package
183
181
  # returns a hash with the keys as the l., ll. searches
184
- # and the values as the replacements in the form of
185
- # an array where the first value is a symbol and the
182
+ # and the values as the replacements in the form of
183
+ # an array where the first value is a symbol and the
186
184
  # second value is the precursor
187
185
 
188
- def set_the_subs_arrays(value)
189
- # takes a core value from the hash pulled from the yaml
190
- # returns an array with a type symbol and a precursor string
191
- if value =~ /I\.\z/ # type1 : {{ I. }}
192
- return[:type1, value[0..-3]]
193
- elsif value =~ /\(I\)\z/ # type2 : {{ (I) }}
194
- return[:type2, value[0..-4]]
195
- elsif value =~ /i\.\z/ # type3 : {{ i. }}
196
- return[:type3, value[0..-3]]
197
- elsif value =~ /\(i\)\z/ # type4 : {{ (i) }}
198
- return[:type4, value[0..-4]]
199
- elsif value =~ /[A-Z]\.\z/ # type5 : {{ A. }}
200
- return[:type5, value[0..-3]]
201
- elsif value =~ /\([A-Z]\)\z/ # type6 : {{ (A) }}
202
- return[:type6, value[0..-4]]
203
- elsif value =~ /[a-z]\.\z/ # type7 : {{ a. }}
204
- return[:type7, value[0..-3]]
205
- elsif value =~ /\([a-z]\)\z/ # type8 : {{ (a) }}
206
- return[:type8, value[0..-4]]
207
- elsif value =~ /\(\d\)\z/ # type9 : {{ (1) }}
208
- return[:type9, value[0..-4]]
209
- else value =~ /\d\.\z/ # type0 : {{ 1. }} ... also default
210
- return[:type0, value[0..-3]]
211
- end
186
+ # @substitutions hash example
187
+ # {"ll." || "l2."=>[:type8, "Article ", "(", "1", ")", :no_reset || nil, " ", :preval || :pre || nil]}
188
+
189
+ @substitutions = {}
190
+ headers["level-style"] == "l1." ? @deep_leaders = true : @deep_leaders = false
191
+ if headers.has_key?("no-indent")
192
+ no_indent_array = headers["no-indent"].split(", ")
193
+ no_indent_array.include?("l." || "l1.") ? @offset = no_indent_array.size : @offset = no_indent_array.size + 1
194
+ else
195
+ @offset = 1
212
196
  end
213
197
 
214
- substitutions = {}
215
198
  headers.each do | header, value |
216
- if header =~ /level-\d/
217
- level = header[-1].to_i
218
- base = "l"
219
- search = base * level + "."
220
- # substitutions hash example {"ll."=>[:type8,"Article"],}
221
- substitutions[search]= set_the_subs_arrays(value.to_s)
199
+ if @deep_leaders
200
+ search = "l" + header[-1] + "." if header =~ /level-\d/
201
+ else
202
+ search = "l" * header[-1].to_i + "." if header =~ /level-\d/
222
203
  end
223
- if header =~ /no-reset/
224
- no_subs_array = value.split(", ")
225
- no_subs_array.each{|e| substitutions[e][6] = :no_reset }
226
- end
227
- @no_indt_array = []
228
- if header =~ /no-indent/
229
- @no_indt_array = value.split(", ")
204
+
205
+ if header =~ /level-\d/
206
+ @substitutions[search]= set_the_subs_arrays(value.to_s)
207
+ @deep_leaders ? spaces = (search[1].to_i - @offset) : spaces = (search.size - @offset - 1)
208
+ spaces < 0 ? spaces = 0 : spaces = spaces * 2
209
+ @substitutions[search][6] = " " * spaces
210
+ if value =~ /\s*preval\s*/
211
+ @substitutions[search][1].gsub!(/preval\s*/, "")
212
+ @substitutions[search][7] = :preval
213
+ elsif value =~ /\s*pre\s*/
214
+ @substitutions[search][1].gsub!(/pre\s*/, "")
215
+ @substitutions[search][7] = :pre
216
+ end
230
217
  end
231
218
  end
232
219
 
233
- return substitutions
220
+ no_subs_array = headers["no-reset"].split(", ")
221
+ no_subs_array.each{ |e| @substitutions[e][5] = :no_reset unless e == "l." || e == "l1."}
222
+
223
+ return @substitutions
234
224
  end
235
225
 
236
226
  def find_the_block( content )
237
- # finds the block of text that will be processed
238
- # returns an array with the first element as the block
239
- # to be processed and the second element as the rest of the document
240
- if content =~ /(^l+\.\s.+^$)/m
241
- block = $1.chomp
242
- content = $PREMATCH + "{{block}}\n" + $POSTMATCH
227
+ block_pattern = /(^```+\s*\n?)(.*?\n?)(^```+\s*\n?)/m
228
+ parts = content.partition( block_pattern )
229
+ if parts[1] != ""
230
+ block = $2.chomp
231
+ content = parts[0] + "{{block}}" + parts[2]
232
+ else
233
+ block = ""
234
+ content = content
243
235
  end
244
- return[ block, content ]
236
+ return [ block, content ]
245
237
  end
246
238
 
247
- def chew_on_the_block( substitutions, block )
239
+ def chew_on_the_block( old_block )
248
240
  # takes a hash of substitutions to make from the #get_the_substitutions method
249
241
  # and a block of text returned from the #find_the_block method
250
242
  # iterates over the block to make the appropriate substitutions
251
243
  # returns a block of text
252
244
 
253
- def get_the_subs_arrays( value )
254
- # returns a new array for the replacements
255
- if value[0] == :type1 # :type1 : {{ I. }}
256
- value[2..4] = [ "", "I", "." ]
257
- return value
258
- elsif value[0] == :type2 # :type2 : {{ (I) }}
259
- value[2..4] = [ "(", "I", ")"]
260
- return value
261
- elsif value[0] == :type3 # :type3 : {{ i. }}
262
- value[2..4] = [ "", "i", "."]
263
- return value
264
- elsif value[0] == :type4 # :type4 : {{ (i) }}
265
- value[2..4] = [ "(", "i", ")"]
266
- return value
267
- elsif value[0] == :type5 # :type5 : {{ A. }}
268
- value[2..4] = [ "", "A", "."]
269
- return value
270
- elsif value[0] == :type6 # :type6 : {{ (A) }}
271
- value[2..4] = [ "(", "A", ")"]
272
- return value
273
- elsif value[0] == :type7 # :type7 : {{ a. }}
274
- value[2..4] = [ "", "a", "."]
275
- return value
276
- elsif value[0] == :type8 # :type8 : {{ (a) }}
277
- value[2..4] = [ "(", "a", ")"]
278
- return value
279
- elsif value[0] == :type9 # :type9 : {{ (1) }}
280
- value[2..4] = [ "(", "1", ")"]
281
- return value
282
- else value[0] == :type0 # :type0 : {{ 1. }} ... also default
283
- value[2..4] = [ "", 1, "."]
284
- return value
245
+ # method will take the old_block and iterate through the lines.
246
+ # First it will find the leading indicator. Then it will
247
+ # find the appropriate substitution from the @substitutions
248
+ # hash. After that it will rebuild the leading matter from the
249
+ # sub hash. It will drop markers if it is going down the tree.
250
+ # It will reset the branches if it is going up the tree.
251
+ # sub_it is an array w/ type[0] & lead_string[1] & id's[2..4]
252
+
253
+ # @substitutions hash example
254
+ # {"ll."OR "l2."=>[:type8, "Article ", "(", "1", ")", :no_reset || nil, :no_indent || nil, :preval || :pre || nil],}
255
+
256
+ def romans_takedown( array_to_sub )
257
+ if array_to_sub[0] == :type1 || array_to_sub[0] == :type2
258
+ @r_u = true
259
+ elsif array_to_sub[0] == :type3 || array_to_sub[0] == :type4
260
+ @r_l = true
285
261
  end
262
+ if @r_l || @r_u
263
+ array_to_sub[3] = RomanNumerals.to_decimal_string(array_to_sub[3])
264
+ end
265
+ return array_to_sub
286
266
  end
287
267
 
288
- def log_the_line( new_block, selector, line, array_to_sub )
289
- substitute = array_to_sub[1..4].join
290
- spaces = ""
291
- unless @no_indt_array.include?(selector)
292
- downgrade_spaces = @no_indt_array.include?("l.") ? @no_indt_array.size - 1 : @no_indt_array.size
293
- spaces = ( " " * ( (selector.size) - 2 - downgrade_spaces ) * 4 )
268
+ def romans_setup( array_to_sub )
269
+ if @r_l || @r_u
270
+ array_to_sub[3] = RomanNumerals.to_roman_upper(array_to_sub[3]) if @r_u
271
+ array_to_sub[3] = RomanNumerals.to_roman_lower(array_to_sub[3]) if @r_l
294
272
  end
295
- new_block << spaces + line.gsub(selector, substitute) + "\n"
273
+ @r_l = false; @r_u = false
274
+ return array_to_sub
296
275
  end
297
276
 
298
- def increment_the_branch( hash_of_subs, array_to_sub, selector )
299
- romans_uppers = [ :type1, :type2 ]
300
- romans_lowers = [ :type3, :type4 ]
301
- romans = romans_uppers + romans_lowers
302
- if romans.any?{ |e| e == array_to_sub[0] }
303
- if romans_lowers.any?{ |e| e == array_to_sub[0] }
304
- r_l = true
305
- else
306
- r_u = true
277
+ def increment_the_branch( array_to_sub, selector, next_selector )
278
+ if selector > next_selector #going up the tree and reset
279
+ selectors_to_reset = @substitutions.inject([]){ |m,(k,v)| m << k if k > next_selector; m }
280
+ selectors_to_reset.each do | this_selector |
281
+ substitutor = @substitutions[this_selector]
282
+ substitutor = romans_takedown( substitutor )
283
+ substitutor[3].next! if this_selector == selector
284
+ if substitutor[0] == :type5 || substitutor[0] == :type6
285
+ substitutor[3] = "A" unless substitutor[5] == :no_reset
286
+ elsif substitutor[0] == :type7 || substitutor[0] == :type8
287
+ substitutor[3] = "a" unless substitutor[5] == :no_reset
288
+ else
289
+ substitutor[3] = "1" unless substitutor[5] == :no_reset
290
+ end
291
+ substitutor = romans_setup( substitutor )
292
+ @substitutions[this_selector]= substitutor
307
293
  end
294
+ array_to_sub = @substitutions[selector]
295
+ else #not going up tree
296
+ array_to_sub = romans_takedown( array_to_sub )
297
+ array_to_sub[3].next!
298
+ array_to_sub = romans_setup( array_to_sub )
308
299
  end
309
- if r_l == true
310
- array_to_sub[3] = array_to_sub[3].upcase
311
- end
312
- if r_l == true || r_u == true
313
- array_to_sub[3] = RomanNumerals.to_decimal(array_to_sub[3])
314
- end
315
- array_to_sub[3] = array_to_sub[3].next
316
- if r_l == true || r_u == true
317
- array_to_sub[3] = RomanNumerals.to_roman(array_to_sub[3])
318
- end
319
- if r_l == true
320
- array_to_sub[3] = array_to_sub[3].downcase
300
+
301
+ return array_to_sub
302
+ end
303
+
304
+ def get_selector_above( selector )
305
+ if @deep_leaders
306
+ selector_above = "l" + (selector[1].to_i-1).to_s + "."
307
+ selector_above = "l1." if selector_above == "l0."
308
+ else
309
+ selector_above = selector[1..-1]
310
+ selector_above = "l." if selector_above == "."
321
311
  end
322
- hash_of_subs[selector]= array_to_sub
323
- return hash_of_subs
312
+ return selector_above
324
313
  end
325
314
 
326
- def reset_the_sub_branches( hash_of_subs, array_to_sub, selector )
327
- hash_of_subs = increment_the_branch( hash_of_subs, array_to_sub, selector )
328
- leaders_to_reset = []
329
- hash_of_subs.each_key{ |k| leaders_to_reset << k if k > selector }
330
- leaders_to_reset.each do | leader |
331
- unless hash_of_subs[leader][6] == :no_reset
332
- unless hash_of_subs[leader][5] == :pre
333
- hash_of_subs[leader]= get_the_subs_arrays(hash_of_subs[leader])
334
- else
335
- hash_of_subs[leader]= get_the_subs_arrays(hash_of_subs[leader])
336
- hash_of_subs[leader]= pre_setup(hash_of_subs[leader])
337
- end
338
- end
315
+ def find_parent_reference( selector_above )
316
+ leading_prov = @substitutions[selector_above].clone
317
+ leading_prov = romans_takedown( leading_prov )
318
+ if leading_prov[0] == :type5 || leading_prov[0] == :type6
319
+ leading_prov[3] = leading_prov[3][0..-2] + (leading_prov[3][-1].ord-1).chr
320
+ elsif leading_prov[0] == :type7 || leading_prov[0] == :type8
321
+ leading_prov[3] = leading_prov[3][0..-2] + (leading_prov[3][-1].ord-1).chr
322
+ else
323
+ leading_prov[3] = (leading_prov[3].to_i-1).to_s
339
324
  end
340
- return hash_of_subs
325
+ leading_prov = romans_setup( leading_prov )
326
+ return leading_prov
341
327
  end
342
328
 
343
- def pre_setup( array_to_sub )
344
- array_to_sub[5] = :pre
345
- array_to_sub[1] = ""
329
+ def preval_substitution( array_to_sub, selector )
330
+ array_to_sub.pop unless array_to_sub.last == :preval
331
+ selector_above = get_selector_above( selector )
332
+ leading_prov = find_parent_reference( selector_above )[3]
333
+ trailing_prov = array_to_sub[3].clone
334
+ trailing_prov.prepend("0") if trailing_prov.size == 1
335
+ array_to_sub << array_to_sub[2] + leading_prov.to_s + trailing_prov.to_s + array_to_sub[4]
336
+ array_to_sub.last.gsub!($1, "(") if array_to_sub.last[/(\.\()/]
346
337
  return array_to_sub
347
338
  end
348
339
 
349
- def reform_the_block( old_block, substitutions )
350
- # method will take the old_block and iterate through the lines.
351
- # First it will find the leading indicator. Then it will
352
- # find the appropriate substitution from the substitutions
353
- # hash. After that it will rebuild the leading matter from the
354
- # sub hash. It will drop markers if it is going down the tree.
355
- # It will reset the branches if it is going up the tree.
356
- # sub_it is an array w/ type[0] & lead_string[1] & id's[2..4]
357
- new_block = ""
358
- leader_before = ""
359
- leader_above = ""
360
- selector_before = ""
361
- old_block.each_line do | line |
362
- selector = $1.chop if line =~ /(^l+.\s)/
363
- sub_it = substitutions[selector]
364
- if sub_it[5] == :pre || sub_it[1] =~ /pre/
365
- sub_it = pre_setup(sub_it)
366
- if selector_before < selector # Going down the tree, into pre
367
- leader_above = substitutions[selector_before][1..4].join
368
- sub_it[1] = leader_above = leader_before
369
- elsif selector_before > selector && substitutions[selector_before][5] == :pre
370
- sub_it[1] = leader_above[0..-3]
371
- else
372
- sub_it[1] = leader_above
373
- end
374
- end
375
- log_the_line( new_block, selector, line, sub_it )
376
- leader_before = sub_it[1..4].join
377
- if selector_before > selector # We are going up the tree.
378
- substitutions = reset_the_sub_branches(substitutions, sub_it, selector)
379
- else # We are at the same level.
380
- substitutions = increment_the_branch(substitutions, sub_it, selector)
381
- end
382
- selector_before = selector
340
+ def pre_substitution( array_to_sub, selector )
341
+ array_to_sub.pop unless array_to_sub.last == :pre
342
+ selector_above = get_selector_above( selector )
343
+ leading_prov = @substitutions[selector_above][8] || find_parent_reference( selector_above )[2..4].join
344
+ trailing_prov = array_to_sub[2..4].join
345
+ array_to_sub << leading_prov + trailing_prov
346
+ array_to_sub.last.gsub!($1, "(") if array_to_sub.last[/(\.\()/]
347
+ return array_to_sub
348
+ end
349
+
350
+ cross_references = {}
351
+ arrayed_block = []
352
+ old_block.each_line do |line|
353
+ next if line[/^\s*\n/]
354
+ line[/(^l+\.)\s*(\|.*?\|)*\s*(.*)$/] ? arrayed_block << [$1, $3, $2] : arrayed_block.last[1] << ("\n" + line.rstrip)
355
+ end
356
+ old_block = "" # for large files
357
+
358
+ new_block = arrayed_block.inject("") do |block, arrayed_line|
359
+
360
+ selector = arrayed_line[0]
361
+ next_selector = ( arrayed_block[arrayed_block.index(arrayed_line)+1] || arrayed_block.last ).first
362
+ sub_it = @substitutions[selector]
363
+
364
+ if arrayed_line[1] =~ /\n/
365
+ arrayed_line[1].gsub!("\n", "\n\n" + sub_it[6])
383
366
  end
384
- return new_block
367
+
368
+ if sub_it[7] == :preval
369
+ sub_it = preval_substitution(sub_it, selector)
370
+ reference = sub_it.last
371
+ elsif sub_it[7] == :pre
372
+ sub_it = pre_substitution(sub_it, selector)
373
+ reference = sub_it.last
374
+ else
375
+ reference = sub_it[2..4].join
376
+ end
377
+
378
+ block << sub_it[6] + sub_it[1] + reference + " " + arrayed_line[1] + "\n\n"
379
+ cross_references[arrayed_line[2]]= sub_it[1] + reference if arrayed_line[2]
380
+ @substitutions[selector]= increment_the_branch(sub_it, selector, next_selector)
381
+
382
+ block
385
383
  end
386
384
 
387
- substitutions.each_key{ |k| substitutions[k]= get_the_subs_arrays(substitutions[k]) }
388
- new_block = reform_the_block( block, substitutions )
385
+ cross_references.each_key{|k| new_block.gsub!(k, cross_references[k]) }
386
+ return new_block
389
387
  end
390
388
 
391
389
  headers = get_the_substitutions( headers )
392
- block_noted = find_the_block( content )
393
- block = block_noted[0]
394
- not_the_block = block_noted[1]
395
- block_noted = "" # Really only for long documents so they don't use too much memory
390
+ block_found = find_the_block( content )
391
+ block = block_found[0]
392
+ not_the_block = block_found[1]
393
+ block_found = "" # for long documents
396
394
 
397
- if block == nil || block == ""
395
+ if block == ""
398
396
  block_redux = ""
399
- elsif headers == {}
397
+ elsif headers == {}
400
398
  block_redux = block
401
399
  else
402
- block_redux = chew_on_the_block( headers, block )
400
+ block_redux = chew_on_the_block( block )
403
401
  end
404
-
405
- headed = not_the_block.gsub("{{block}}", block_redux )
402
+ headed = not_the_block.gsub("{{block}}", block_redux )
406
403
  end
407
404
 
408
405
  # ----------------------
409
406
  # | Step 6 |
410
407
  # ----------------------
411
- # Write the file
412
-
413
- def write_it( filename, final_content )
414
- if File.writable?( filename )
415
- File::open filename, 'w' do |f|
416
- f.write final_content
417
- end
408
+ # Write the file
409
+ def write_it( final_content )
410
+ if @output_file && @output_file != "-"
411
+ File.open(@output_file, "w") {|f| f.write( final_content ) }
412
+ else
413
+ STDOUT.write final_content
418
414
  end
419
415
  end
420
416
  end