legal_markdown 0.1.5 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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