legal_markdown 0.4.7 → 0.4.8
Sign up to get free protection for your applications and to get access to all the features.
- data/legal_markdown.gemspec +1 -1
- data/lib/legal_markdown.rb +19 -10
- data/lib/legal_markdown/legal_to_markdown.rb +68 -10
- data/lib/legal_markdown/legal_to_markdown/load_source.rb +9 -1
- data/lib/legal_markdown/legal_to_markdown/writer.rb +1 -1
- data/lib/legal_markdown/make_yaml_frontmatter.rb +63 -41
- data/lib/legal_markdown/version.rb +1 -1
- data/test/legal_markdown_test.rb +43 -21
- data/test/tests/20.block_no_addons.lmd +1 -1
- data/test/tests/45.all_features_speed_ratchet.debug +551 -0
- metadata +22 -4
data/legal_markdown.gemspec
CHANGED
data/lib/legal_markdown.rb
CHANGED
@@ -19,8 +19,8 @@ module LegalMarkdown
|
|
19
19
|
opt_parser = OptionParser.new do |opt|
|
20
20
|
opt.banner = "Usage: legal2md [commands] [input_file] [output_file]"
|
21
21
|
opt.separator ""
|
22
|
-
opt.separator "[input_file] can be a file
|
23
|
-
opt.separator "[output_file] can be a file
|
22
|
+
opt.separator "[input_file] can be a file or use \"-\" for STDIN"
|
23
|
+
opt.separator "[output_file] can be a file or use \"-\" for STDOUT"
|
24
24
|
opt.separator ""
|
25
25
|
opt.separator "Specific Commands:"
|
26
26
|
|
@@ -34,6 +34,11 @@ module LegalMarkdown
|
|
34
34
|
config[:output][:jason] = true
|
35
35
|
end
|
36
36
|
|
37
|
+
config[:verbose] = false
|
38
|
+
opt.on('--verbose', 'Debug legal_markdown. Only works with output options, not with headers switch.') do
|
39
|
+
config[:verbose] = true
|
40
|
+
end
|
41
|
+
|
37
42
|
config[:headers] = false
|
38
43
|
opt.on( '-d', '--headers', 'Make the YAML Frontmatter automatically.' ) do
|
39
44
|
config[:headers] = true
|
@@ -49,7 +54,7 @@ module LegalMarkdown
|
|
49
54
|
args.delete(:to_json) if args.include?( :to_json )
|
50
55
|
end
|
51
56
|
|
52
|
-
if args.include? :to_markdown
|
57
|
+
if args.include? :to_markdown || (begin args[-1][/\.md|\.markdown/]; rescue; end;)
|
53
58
|
config[:output][:markdown] = true
|
54
59
|
args.delete :markdown
|
55
60
|
end
|
@@ -68,18 +73,22 @@ module LegalMarkdown
|
|
68
73
|
opt.separator "Notes:"
|
69
74
|
opt.separator "If the command is --headers or with --to-markdown you can enter one file to be parsed if you wish."
|
70
75
|
opt.separator "When these commands are called with only one file I will set the input_file and the output_file to be the same."
|
71
|
-
opt.separator "The other commands will require the original legal_markdown file and the output
|
76
|
+
opt.separator "The other commands will require the original legal_markdown file and the output file."
|
72
77
|
opt.separator "There is no need to explicitly enter the --to-json if your output_file is *.json I can handle it."
|
78
|
+
opt.separator "There is no need to explicitly enter the --to-markdown if your output_file is *.md or *.markdown I can handle it."
|
73
79
|
opt.separator ""
|
74
80
|
end
|
81
|
+
|
75
82
|
opt_parser.parse!(args)
|
76
83
|
|
77
|
-
if
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
84
|
+
if args.size >= 1
|
85
|
+
if config[:headers]
|
86
|
+
MakeYamlFrontMatter.new(args)
|
87
|
+
elsif config[:output][:jason]
|
88
|
+
LegalToMarkdown.parse_jason(args, config[:verbose])
|
89
|
+
elsif config[:output][:markdown] || args.size <= 2
|
90
|
+
LegalToMarkdown.parse_markdown(args, config[:verbose])
|
91
|
+
end
|
83
92
|
else
|
84
93
|
puts opt_parser
|
85
94
|
end
|
@@ -5,25 +5,83 @@ require 'legal_to_markdown/leaders.rb'
|
|
5
5
|
require 'legal_to_markdown/json_builder.rb'
|
6
6
|
require 'legal_to_markdown/writer.rb'
|
7
7
|
require 'roman_numerals'
|
8
|
+
require 'paint'
|
8
9
|
|
9
10
|
module LegalToMarkdown
|
10
11
|
|
11
|
-
def parse_markdown
|
12
|
-
|
13
|
-
|
14
|
-
source
|
15
|
-
|
16
|
-
|
17
|
-
|
12
|
+
def parse_markdown args, verbosity
|
13
|
+
parse_setup args, verbosity
|
14
|
+
source = FileToParse.new(@input_file, :markdown)
|
15
|
+
parse_controller source
|
16
|
+
end
|
17
|
+
|
18
|
+
def parse_jason args, verbosity
|
19
|
+
parse_setup args, verbosity
|
20
|
+
source = FileToParse.new(@input_file, :jason)
|
21
|
+
parse_controller source
|
18
22
|
end
|
19
23
|
|
20
|
-
|
24
|
+
private
|
25
|
+
|
26
|
+
def parse_setup args, verbosity
|
21
27
|
@input_file = args[-2] ? args[-2] : args[-1]
|
22
28
|
@output_file = args[-1]
|
23
|
-
|
29
|
+
@verbose = true if verbosity
|
30
|
+
end
|
31
|
+
|
32
|
+
def parse_controller source
|
33
|
+
verbose_after_load source if @verbose
|
24
34
|
source.run_mixins if source.mixins
|
35
|
+
verbose_after_mixins source if @verbose
|
25
36
|
source.run_leaders if source.leaders
|
26
|
-
source
|
37
|
+
verbose_after_leaders source if @verbose
|
38
|
+
source.build_jason if source.writer == :jason
|
27
39
|
write_it(source.content, source.writer)
|
28
40
|
end
|
41
|
+
|
42
|
+
def verbose_after_load source
|
43
|
+
puts
|
44
|
+
puts
|
45
|
+
puts Paint["Here's what I found after loading.", :blue, :bold]
|
46
|
+
puts Paint['==================================', :blue]
|
47
|
+
puts
|
48
|
+
puts Paint["The Headers I found are:", :green, :bold]
|
49
|
+
puts Paint['------------------------', :green]
|
50
|
+
puts Paint[(source.headers), :magenta]
|
51
|
+
puts
|
52
|
+
puts Paint["The Content I found is:", :green, :bold]
|
53
|
+
puts Paint['-----------------------', :green]
|
54
|
+
puts Paint[(source.content), :yellow]
|
55
|
+
puts
|
56
|
+
puts Paint["There are MIXINS to be parsed.", :red, :bold] if source.mixins
|
57
|
+
puts Paint["There are STRUCTURED HEADERS to be parsed.", :red, :bold] if source.leaders
|
58
|
+
end
|
59
|
+
|
60
|
+
def verbose_after_mixins source
|
61
|
+
puts
|
62
|
+
puts Paint["Here's what I found after the mixins.", :blue, :bold]
|
63
|
+
puts Paint['=====================================', :blue]
|
64
|
+
puts
|
65
|
+
puts Paint["The Headers I found are:", :green, :bold]
|
66
|
+
puts Paint['------------------------', :green]
|
67
|
+
puts Paint[(source.headers), :magenta]
|
68
|
+
puts
|
69
|
+
puts Paint["The Content I found is:", :green, :bold]
|
70
|
+
puts Paint['-----------------------', :green]
|
71
|
+
puts Paint[(source.content), :yellow]
|
72
|
+
end
|
73
|
+
|
74
|
+
def verbose_after_leaders source
|
75
|
+
puts
|
76
|
+
puts Paint["Here's what I found after the headers.", :blue, :bold]
|
77
|
+
puts Paint['=====================================', :blue]
|
78
|
+
puts
|
79
|
+
puts Paint["The Headers I found are:", :green, :bold]
|
80
|
+
puts Paint['------------------------', :green]
|
81
|
+
puts Paint[(source.headers), :magenta]
|
82
|
+
puts
|
83
|
+
puts Paint["The Content I found is:", :green, :bold]
|
84
|
+
puts Paint['-----------------------', :green]
|
85
|
+
puts Paint[(source.content), :yellow]
|
86
|
+
end
|
29
87
|
end
|
@@ -6,7 +6,7 @@ module LegalToMarkdown
|
|
6
6
|
attr_accessor :headers, :content, :mixins, :leaders, :writer
|
7
7
|
|
8
8
|
def initialize(file, output)
|
9
|
-
@input_file = file; @headers = nil; @content = ""; @writer = output
|
9
|
+
@input_file = file; @headers = nil; @content = ""; @writer = output
|
10
10
|
load; get_the_partials; parse; set_the_parsers
|
11
11
|
end
|
12
12
|
|
@@ -41,6 +41,7 @@ module LegalToMarkdown
|
|
41
41
|
yaml_pattern = /\A(---\s*\n.*?\n?)^(---\s*$\n?)/m
|
42
42
|
parts = @content.partition yaml_pattern
|
43
43
|
if parts[1] != ""
|
44
|
+
parts[1] = string_guard parts[1]
|
44
45
|
@headers = YAML.load parts[1]
|
45
46
|
@content = parts[2]
|
46
47
|
end
|
@@ -74,5 +75,12 @@ module LegalToMarkdown
|
|
74
75
|
d = Date.today.strftime("%-d %B, %Y")
|
75
76
|
@content.gsub!(/@today/, d)
|
76
77
|
end
|
78
|
+
|
79
|
+
def string_guard strings
|
80
|
+
if strings =~ /(:\s*(\d+\.))$/
|
81
|
+
strings = strings.gsub($1, ": \"" + $2 + "\"" )
|
82
|
+
end
|
83
|
+
strings
|
84
|
+
end
|
77
85
|
end
|
78
86
|
end
|
@@ -6,7 +6,7 @@ module LegalToMarkdown
|
|
6
6
|
require 'json' if writer == :jason
|
7
7
|
if @output_file && @output_file != "-"
|
8
8
|
File.open(@output_file, "w") {|f| f.write( final_content ); f.close } if writer == :markdown
|
9
|
-
File.open(@output_file, "w") { |f| JSON.
|
9
|
+
File.open(@output_file, "w") { |f| IO.write( f, JSON.pretty_generate( final_content ) ); f.close } if writer == :jason
|
10
10
|
else
|
11
11
|
STDOUT.write final_content
|
12
12
|
end
|
@@ -4,39 +4,32 @@ require 'yaml'
|
|
4
4
|
class MakeYamlFrontMatter
|
5
5
|
|
6
6
|
def initialize(args)
|
7
|
-
|
7
|
+
@input_file = args[-2] ? args[-2] : args[-1]
|
8
|
+
@output_file = args[-1]
|
9
|
+
find_yaml_if_yaml load
|
8
10
|
scan_and_filter_yaml
|
9
11
|
build_new_yaml_frontmatter unless @yaml_data_as_array == [{},{},{},{}]
|
10
12
|
write_it
|
11
13
|
end
|
12
14
|
|
13
|
-
|
15
|
+
private
|
16
|
+
|
17
|
+
def load
|
14
18
|
begin
|
15
|
-
@input_file
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
else
|
20
|
-
source_file = STDIN.read
|
21
|
-
end
|
22
|
-
source_file.scan(/(@include (.+)$)/).each do |set|
|
23
|
-
partial_file = set[1]
|
24
|
-
to_replace = set[0]
|
25
|
-
partial_contents = File::read(partial_file) if File::exists?(partial_file) && File::readable?(partial_file)
|
26
|
-
source_file.gsub!(to_replace, "[PARTIALSTART]\n" + partial_contents + "\n[PARTIALENDS][#{to_replace}]")
|
27
|
-
end
|
28
|
-
return source_file
|
29
|
-
rescue => e
|
30
|
-
puts "Sorry, I could not read the input file #{@input_file}: #{e.message}."
|
19
|
+
source_file = @input_file == "-" ? STDIN.read : File::read(@input_file)
|
20
|
+
source_file = guard_partials_start source_file
|
21
|
+
rescue
|
22
|
+
puts "Sorry, I could not read the input file #{@input_file}."
|
31
23
|
exit 0
|
32
24
|
end
|
33
25
|
end
|
34
26
|
|
35
|
-
def find_yaml_if_yaml
|
27
|
+
def find_yaml_if_yaml source
|
36
28
|
yaml_pattern = /\A(---\s*\n.*?\n?)^(---\s*$\n?)/m
|
37
|
-
parts = source.partition
|
38
|
-
if parts[1]
|
39
|
-
|
29
|
+
parts = source.partition yaml_pattern
|
30
|
+
if ! parts[1].empty?
|
31
|
+
parts[1] = guard_strings parts[1]
|
32
|
+
@headers = YAML.load parts[1]
|
40
33
|
@content = parts[2]
|
41
34
|
else
|
42
35
|
@headers = {}
|
@@ -49,9 +42,9 @@ class MakeYamlFrontMatter
|
|
49
42
|
opt_clauses_pattern = /\[{{(\S+)}}/
|
50
43
|
@structured_headers_pattern = /(^l+.|^l\d+.)/
|
51
44
|
@yaml_data_as_array = []
|
52
|
-
@yaml_data_as_array << ( filter_yaml
|
53
|
-
@yaml_data_as_array << ( filter_yaml
|
54
|
-
@yaml_data_as_array << ( filter_yaml
|
45
|
+
@yaml_data_as_array << ( filter_yaml mixin_pattern || {} )
|
46
|
+
@yaml_data_as_array << ( filter_yaml opt_clauses_pattern || {} )
|
47
|
+
@yaml_data_as_array << ( filter_yaml @structured_headers_pattern || {} )
|
55
48
|
@yaml_data_as_array << ( @yaml_data_as_array.last.empty? ? {} : filter_yaml(%w{no-indent no-reset level-style}) )
|
56
49
|
end
|
57
50
|
|
@@ -70,11 +63,7 @@ class MakeYamlFrontMatter
|
|
70
63
|
end
|
71
64
|
|
72
65
|
def write_it
|
73
|
-
|
74
|
-
replacer = set[1]
|
75
|
-
to_replace = set[0]
|
76
|
-
@content.gsub!(to_replace, replacer)
|
77
|
-
end
|
66
|
+
guard_partials_finish
|
78
67
|
if @output_file && @output_file != "-"
|
79
68
|
File.open(@output_file, "w") {|f| f.write( @content ); f.close }
|
80
69
|
else
|
@@ -82,7 +71,17 @@ class MakeYamlFrontMatter
|
|
82
71
|
end
|
83
72
|
end
|
84
73
|
|
85
|
-
def
|
74
|
+
def filter_yaml pattern
|
75
|
+
# @headers will be a hash, stuff is an array, returns a filtered hash
|
76
|
+
stuff = pattern.is_a?(Regexp) ? scan_doc(pattern) : pattern
|
77
|
+
if stuff
|
78
|
+
stuff_in_yaml = stuff.inject({}) do |hash, elem|
|
79
|
+
@headers.has_key?(elem) ? hash.merge({elem => @headers[elem]}) : hash.merge({elem => ""})
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def scan_doc pattern
|
86
85
|
found = @content.scan(pattern).uniq.sort.flatten
|
87
86
|
if pattern == @structured_headers_pattern
|
88
87
|
found = convert_ll_to_level_two found
|
@@ -90,24 +89,47 @@ class MakeYamlFrontMatter
|
|
90
89
|
found
|
91
90
|
end
|
92
91
|
|
93
|
-
def convert_ll_to_level_two
|
92
|
+
def convert_ll_to_level_two levels
|
94
93
|
# receives an array in form ["l.", "ll.", "lll."] returns array in form ["level-1", "level-2"]
|
95
|
-
levels.inject([])
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
stuff_in_yaml = stuff.inject({}) do |hash, elem|
|
102
|
-
@headers.has_key?(elem) ? hash.merge({elem => @headers[elem]}) : hash.merge({elem => ""})
|
94
|
+
levels.inject([]) do |arr, level|
|
95
|
+
level[/((l+)\.)|(l(\d+)\.*)/]
|
96
|
+
if $2
|
97
|
+
arr << "level-" + $2.length.to_s
|
98
|
+
else
|
99
|
+
arr << "level-" + $&.delete("l")
|
103
100
|
end
|
104
101
|
end
|
105
102
|
end
|
106
103
|
|
107
|
-
def sink_it
|
104
|
+
def sink_it section
|
108
105
|
section.inject("") do |string, head|
|
109
106
|
string << head[0] + ": \"" + ( head[1].to_s.gsub("\"", "\\\"") || "" ) + "\"\n"
|
110
107
|
string
|
111
108
|
end
|
112
109
|
end
|
110
|
+
|
111
|
+
def guard_partials_start source_file
|
112
|
+
source_file.scan(/(@include (.+)$)/).each do |set|
|
113
|
+
partial_file = set[1]
|
114
|
+
to_replace = set[0]
|
115
|
+
partial_contents = File::read(partial_file) if File::exists?(partial_file) && File::readable?(partial_file)
|
116
|
+
source_file.gsub!(to_replace, "[PARTIALSTART]\n" + partial_contents + "\n[PARTIALENDS][#{to_replace}]")
|
117
|
+
end
|
118
|
+
source_file
|
119
|
+
end
|
120
|
+
|
121
|
+
def guard_strings strings
|
122
|
+
if strings =~ /(:\s*(\d+\.))$/
|
123
|
+
strings = strings.gsub($1, ": \"" + $2 + "\"" )
|
124
|
+
end
|
125
|
+
strings
|
126
|
+
end
|
127
|
+
|
128
|
+
def guard_partials_finish
|
129
|
+
@content.scan(/(\[PARTIALSTART\].*?\[PARTIALENDS\]\[(.*?)\])/m).each do |set|
|
130
|
+
replacer = set[1]
|
131
|
+
to_replace = set[0]
|
132
|
+
@content.gsub!(to_replace, replacer)
|
133
|
+
end
|
134
|
+
end
|
113
135
|
end
|
data/test/legal_markdown_test.rb
CHANGED
@@ -41,6 +41,41 @@ class TestLegalMarkdownToMarkdown < Test::Unit::TestCase
|
|
41
41
|
hash["nodes"].each_value.collect{|v| v["data"]["content"] if v["data"] && v["data"]["content"]}.select{|v| v}
|
42
42
|
end
|
43
43
|
|
44
|
+
def test_bad_command_line_calls
|
45
|
+
puts "Testing bad file name.\n\n"
|
46
|
+
puts "Testing => legal2md -m 12345.lmd 12345.md"
|
47
|
+
cmd = `legal2md -m 12345.lmd 12345.md`
|
48
|
+
assert_equal( cmd, "Sorry, I could not read the file 12345.lmd: No such file or directory - 12345.lmd.\n" )
|
49
|
+
puts "Testing => legal2md -m"
|
50
|
+
cmd = `legal2md -m`
|
51
|
+
if RUBY_VERSION == "2.0.0"
|
52
|
+
response = "Sorry, I could not read the file to_markdown: no implicit conversion of Symbol into String.\n"
|
53
|
+
else
|
54
|
+
response = "Sorry, I could not read the file to_markdown: can't convert Symbol into String.\n"
|
55
|
+
end
|
56
|
+
assert_equal( cmd, response )
|
57
|
+
puts "Testing => legal2md 12345.md"
|
58
|
+
cmd = `legal2md 12345.md`
|
59
|
+
assert_equal( cmd, "Sorry, I could not read the file 12345.md: No such file or directory - 12345.md.\n" )
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_good_command_line_calls
|
63
|
+
puts "\n\nTesting the command line caller.\n\n"
|
64
|
+
cmds = [ "--headers", "--to-markdown", "--to-json", '', '' ]
|
65
|
+
file = "00.load_write_no_action.lmd"
|
66
|
+
output = ['', create_temp('.md'), create_temp('.json'), create_temp('.md'), create_temp('.json')]
|
67
|
+
puts "Testing => cat 00.load_write_no_action.lmd | legal2md - -"
|
68
|
+
stdin_out_only = `cat 00.load_write_no_action.lmd | legal2md - -`
|
69
|
+
assert_equal(get_file(file), stdin_out_only)
|
70
|
+
cmds = cmds.each{|l| l << (" " + file) }.zip(output)
|
71
|
+
cmds.each do |cmd|
|
72
|
+
cmd = 'legal2md ' + cmd.join(' ')
|
73
|
+
puts "Testing => #{cmd}"
|
74
|
+
`#{cmd}`
|
75
|
+
assert_equal(get_file(file), get_file('00.load_write_no_action.md'))
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
44
79
|
def test_markdown_files
|
45
80
|
puts "\n\nTesting lmd to markdown files.\n\n"
|
46
81
|
@lmdfiles.each do | lmd_file |
|
@@ -83,26 +118,13 @@ class TestLegalMarkdownToMarkdown < Test::Unit::TestCase
|
|
83
118
|
end
|
84
119
|
end
|
85
120
|
|
86
|
-
def
|
87
|
-
puts "\n\nTesting
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
cmds = cmds.each{|l| l << (" " + file) }.zip(output)
|
95
|
-
cmds.each do |cmd|
|
96
|
-
cmd = 'legal2md ' + cmd.join(' ')
|
97
|
-
puts "Testing => #{cmd}"
|
98
|
-
`#{cmd}`
|
99
|
-
assert_equal(get_file(file), get_file('00.load_write_no_action.md'))
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
def test_bad_filename
|
104
|
-
puts "Testing bad file name.\n\n"
|
105
|
-
cmd = `legal2md -m 12345.lmd 12345.md`
|
106
|
-
assert_equal( cmd, "Sorry, I could not read the file 12345.lmd: No such file or directory - 12345.lmd.\n" )
|
121
|
+
def test_zee_verbosity_engine
|
122
|
+
puts "\n\nTesting Verbose.\n\n"
|
123
|
+
temp_file = create_temp('.md')
|
124
|
+
benchmark_file = '45.all_features_speed_ratchet.debug'
|
125
|
+
puts "Testing => legal2md --verbose 45.all_features_speed_ratchet.lmd - > #{temp_file}"
|
126
|
+
`legal2md --verbose 45.all_features_speed_ratchet.lmd - > #{temp_file}`
|
127
|
+
assert_equal( get_file(benchmark_file), get_file(temp_file) )
|
128
|
+
destroy_temp temp_file
|
107
129
|
end
|
108
130
|
end
|