nandoc 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +124 -0
- data/Rakefile +53 -0
- data/bin/nandoc +6 -0
- data/doc/CREDITS.md +6 -0
- data/doc/FAQ/why-not-wiki.md +20 -0
- data/doc/FAQ.md +68 -0
- data/doc/TODOs-and-BUGs.md +15 -0
- data/doc/bar/baz.md +4 -0
- data/doc/bar/bliff.md +8 -0
- data/doc/foo.md +5 -0
- data/doc/getting-started.rb +13 -0
- data/doc/svg/less-fonts.svg +21 -0
- data/lib/nandoc/commands/create-nandoc-site.rb +225 -0
- data/lib/nandoc/commands/diff.rb +279 -0
- data/lib/nandoc/config.rb +58 -0
- data/lib/nandoc/cri-hacks.rb +13 -0
- data/lib/nandoc/data-source.rb +239 -0
- data/lib/nandoc/filters.rb +661 -0
- data/lib/nandoc/helpers/menu-bouncy.rb +109 -0
- data/lib/nandoc/helpers/site-map.rb +157 -0
- data/lib/nandoc/helpers/top-nav.rb +47 -0
- data/lib/nandoc/helpers.rb +42 -0
- data/lib/nandoc/item-class-hacks.rb +57 -0
- data/lib/nandoc/nandoc.persistent.json +3 -0
- data/lib/nandoc/parse-readme.rb +95 -0
- data/lib/nandoc/spec-doc/mini-test/spec-instance-methods.rb +0 -0
- data/lib/nandoc/spec-doc/mini-test.rb +105 -0
- data/lib/nandoc/spec-doc/mock-prompt.rb +121 -0
- data/lib/nandoc/spec-doc/support-modules.rb +158 -0
- data/lib/nandoc/spec-doc/test-case-agent.rb +57 -0
- data/lib/nandoc/spec-doc/test-framework-dispatcher.rb +15 -0
- data/lib/nandoc/spec-doc/test-framework-proxy.rb +78 -0
- data/lib/nandoc/spec-doc.rb +46 -0
- data/lib/nandoc/support/diff-proxy.rb +113 -0
- data/lib/nandoc/support/orphanage.rb +77 -0
- data/lib/nandoc/support/path-tardo.rb +85 -0
- data/lib/nandoc/support/regexp-enhance.rb +76 -0
- data/lib/nandoc/support/site-diff.rb +46 -0
- data/lib/nandoc/support/site-merge.rb +62 -0
- data/lib/nandoc/support/site-methods.rb +69 -0
- data/lib/nandoc/support/stream-colorizer.rb +203 -0
- data/lib/nandoc/support-modules.rb +270 -0
- data/lib/nandoc/test/diff-to-string.rb +251 -0
- data/lib/nandoc/test/minitest-extlib.rb +53 -0
- data/lib/nandoc/treebis/NOGIT-DOCS/NEWS.md +5 -0
- data/lib/nandoc/treebis/NOGIT-README.md +65 -0
- data/lib/nandoc/treebis/nandoc.persistent.json +3 -0
- data/lib/nandoc.rb +48 -0
- data/proto/README.md +31 -0
- data/proto/default/Rakefile +1 -0
- data/proto/default/Rules +46 -0
- data/proto/default/config.yaml +57 -0
- data/proto/default/content/css/nanoc-dist-altered.css +213 -0
- data/proto/default/content/css/trollop-subset.css +116 -0
- data/proto/default/content/js/menu-bouncy.js +126 -0
- data/proto/default/content/stylesheet.css.diff +20 -0
- data/proto/default/content/vendor/jquery-1.3.js +4241 -0
- data/proto/default/content/vendor/jquery.easing.1.3.js +205 -0
- data/proto/default/layouts/default.html +70 -0
- data/proto/default/lib/default.orig.rb +2 -0
- data/proto/default/lib/default.rb +5 -0
- data/proto/default/treebis-task.rb +28 -0
- data/proto/misc/orphan-surrogate.md +6 -0
- data/test/test.rb +102 -0
- metadata +166 -0
@@ -0,0 +1,85 @@
|
|
1
|
+
module NanDoc
|
2
|
+
module PathTardo
|
3
|
+
#
|
4
|
+
# This is like a really basic xpath for data structures
|
5
|
+
# that are composed of arrays and hashes
|
6
|
+
#
|
7
|
+
def tardo_array_index str
|
8
|
+
/\A\[(-?\d+)\]\Z/ =~ str ? $1.to_i : nil
|
9
|
+
end
|
10
|
+
module_function :tardo_array_index
|
11
|
+
|
12
|
+
def hash_to_paths hash, prefix=nil
|
13
|
+
paths = []
|
14
|
+
hash.each do |k,v|
|
15
|
+
ch_prefix = [prefix, k].compact.join('/')
|
16
|
+
if v.kind_of?(Hash)
|
17
|
+
paths.concat hash_to_paths(v, ch_prefix)
|
18
|
+
else
|
19
|
+
paths.push ch_prefix
|
20
|
+
end
|
21
|
+
end
|
22
|
+
paths
|
23
|
+
end
|
24
|
+
|
25
|
+
def path_tardo hash_or_array, path_tardo, prefix = ''
|
26
|
+
/\A([^\/]+)(?:\/(.+))?\Z/ =~ path_tardo or
|
27
|
+
fail("no parse: #{path_tardo}")
|
28
|
+
head, tail = $1, $2
|
29
|
+
value = nil
|
30
|
+
found = nil
|
31
|
+
if idx = tardo_array_index(head)
|
32
|
+
if idx > 0 && idx >= hash_or_array.size
|
33
|
+
found = false
|
34
|
+
elsif idx < 0 && (idx*-1) > hash_or_array.size
|
35
|
+
found = false
|
36
|
+
else
|
37
|
+
found = true
|
38
|
+
value = hash_or_array.slice(idx)
|
39
|
+
end
|
40
|
+
else
|
41
|
+
if hash_or_array.key?(head)
|
42
|
+
found = true
|
43
|
+
value = hash_or_array[head]
|
44
|
+
else
|
45
|
+
found = false
|
46
|
+
end
|
47
|
+
end
|
48
|
+
if ! found
|
49
|
+
Tardo::NotFound.new(prefix, head, hash_or_array)
|
50
|
+
elsif tail
|
51
|
+
local_full_path =
|
52
|
+
[ prefix.empty? ? nil : prefix, head ].compact.join('/')
|
53
|
+
path_tardo(value, tail, local_full_path)
|
54
|
+
else
|
55
|
+
Tardo::Found.new(value)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
module Tardo
|
59
|
+
class NotFound < Struct.new(:prefix, :head, :hash_or_array)
|
60
|
+
def found?; false end
|
61
|
+
def error_message
|
62
|
+
sub_msg =
|
63
|
+
if idx = PathTardo.tardo_array_index(head)
|
64
|
+
"#{idx} is a nonexistant offset"
|
65
|
+
else
|
66
|
+
"a \"#{head}\" key does not exist"
|
67
|
+
end
|
68
|
+
context_msg =
|
69
|
+
if prefix.empty?
|
70
|
+
nil
|
71
|
+
elsif hash_or_array.kind_of?(Array)
|
72
|
+
"in \"#{prefix}\" array,"
|
73
|
+
else
|
74
|
+
"in hash \"#{prefix}\","
|
75
|
+
end
|
76
|
+
msg = [context_msg, sub_msg].compact.join(' ')
|
77
|
+
msg
|
78
|
+
end
|
79
|
+
end
|
80
|
+
class Found < Struct.new(:value)
|
81
|
+
def found?; true end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module NanDoc
|
2
|
+
module RegexpEnhance
|
3
|
+
#
|
4
|
+
# Just gives pre-1.9 regexes the ability to have named captures
|
5
|
+
#
|
6
|
+
# Usage:
|
7
|
+
#
|
8
|
+
# re = /(foo*)bar(baz*)/
|
9
|
+
# RegexpEnhance.names(re, :the_foo, :the_baz)
|
10
|
+
# md = re.match("fooobarbazzzz")
|
11
|
+
# md[:the_foo] # => 'fooo'
|
12
|
+
#
|
13
|
+
class << self
|
14
|
+
def names re, *list
|
15
|
+
to(re) do |re|
|
16
|
+
re.names(*list)
|
17
|
+
end
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
def to re, &block
|
21
|
+
re.extend(self)
|
22
|
+
re.regexp_enhance_init
|
23
|
+
block.call(re)
|
24
|
+
nil
|
25
|
+
end
|
26
|
+
end
|
27
|
+
def regexp_enhance_init
|
28
|
+
@names ||= []
|
29
|
+
class << self
|
30
|
+
alias_method :orig_match, :match
|
31
|
+
def match str
|
32
|
+
md = super
|
33
|
+
MatchData.to(md, self) if md
|
34
|
+
md
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
def names *list
|
39
|
+
if list.any?
|
40
|
+
@names = list
|
41
|
+
else
|
42
|
+
@names
|
43
|
+
end
|
44
|
+
end
|
45
|
+
module MatchData
|
46
|
+
class << self
|
47
|
+
def to(md, re)
|
48
|
+
md.extend self
|
49
|
+
md.match_data_enhanced_init(re)
|
50
|
+
nil
|
51
|
+
end
|
52
|
+
end
|
53
|
+
def match_data_enhanced_init re
|
54
|
+
@names = re.names
|
55
|
+
class << self # @todo see if this doesn't break by moving defs out
|
56
|
+
alias_method :fetch_orig, :[]
|
57
|
+
attr_reader :names
|
58
|
+
def [](mixed)
|
59
|
+
return fetch_orig(mixed) unless mixed.kind_of?(Symbol)
|
60
|
+
fail("no such named capture: #{mixed.inspect}") unless
|
61
|
+
@names.include?(mixed)
|
62
|
+
offset = @names.index(mixed) + 1
|
63
|
+
fetch_orig offset
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
#
|
69
|
+
# @return [Hash] of the named captures in the MatchData
|
70
|
+
#
|
71
|
+
def to_hash
|
72
|
+
Hash[ names.map{ |n| [n, self[n] ] } ]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require File.dirname(__FILE__)+'/diff-proxy.rb'
|
2
|
+
|
3
|
+
module NanDoc
|
4
|
+
class SiteDiff
|
5
|
+
#
|
6
|
+
# This is a reworking of what's in site-merge (which doesn't really
|
7
|
+
# do anything useful attotw, if it still even works.)
|
8
|
+
# it's a wrapper around diff proxy that knows what folder(s) & file(s) we
|
9
|
+
# do and don't want to take into account when showing a sitewide diff.
|
10
|
+
# Specifically it's expected use is for comparing <my-site>/(* ~ output)
|
11
|
+
# with its protoype.
|
12
|
+
#
|
13
|
+
|
14
|
+
include NanDoc::Config::Accessors # file_utils()
|
15
|
+
include NanDoc::PathTardo # debug-ging e.g. hash_to_paths()
|
16
|
+
NanDoc.persistent_delegate_to(self) # empty_tmpdir()
|
17
|
+
include Treebis::DirAsHash # dir_as_hash()
|
18
|
+
include Treebis::Capture3 # capture3()
|
19
|
+
|
20
|
+
def initialize src_path, dest_path
|
21
|
+
@skip_these = %w(
|
22
|
+
output
|
23
|
+
tmp
|
24
|
+
**/*.orig.rb
|
25
|
+
**/*.diff
|
26
|
+
treebis-task.rb
|
27
|
+
)
|
28
|
+
@src_path, @dst_path = src_path, dest_path
|
29
|
+
end
|
30
|
+
|
31
|
+
def get_diff_object
|
32
|
+
file_utils.notice('comparing these:',
|
33
|
+
"#{@src_path.inspect} -> #{@dst_path.inspect}"
|
34
|
+
)
|
35
|
+
src_hash = dir_as_hash(@src_path, :skip => @skip_these)
|
36
|
+
dst_hash = dir_as_hash(@dst_path, :skip => @skip_these)
|
37
|
+
dir = empty_tmpdir('site-diff')
|
38
|
+
src_path = dir + '/a'
|
39
|
+
dst_path = dir + '/b'
|
40
|
+
hash_to_dir src_hash, src_path, file_utils
|
41
|
+
hash_to_dir dst_hash, dst_path, file_utils
|
42
|
+
diff = NanDoc::DiffProxy.diff(src_path, dst_path, :relative_to=>dir)
|
43
|
+
diff
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require File.dirname(__FILE__)+'/diff-proxy.rb'
|
2
|
+
|
3
|
+
module NanDoc
|
4
|
+
class SiteMerge
|
5
|
+
include Treebis::DirAsHash
|
6
|
+
include Treebis::Capture3
|
7
|
+
NanDoc.persistent_delegate_to(self) # empty_tmpdir()
|
8
|
+
|
9
|
+
def initialize site_creator
|
10
|
+
@creator = site_creator
|
11
|
+
end
|
12
|
+
def site_merge opts, args
|
13
|
+
existing_site_path = args.first
|
14
|
+
task_abort("it's not exist: #{path}") unless
|
15
|
+
File.exist?(existing_site_path)
|
16
|
+
# nanoc writes to stdout so we do too, but here we want to write
|
17
|
+
# to stderr these notices, and write the diff to stdout
|
18
|
+
out, err, diff = capture3 do
|
19
|
+
$stdout.puts(
|
20
|
+
"#------------------ (this is for the merge hack:) -----------------")
|
21
|
+
@tmpdir = empty_tmpdir('ridiculous')
|
22
|
+
existing_subset_path = temp_site_subset(existing_site_path)
|
23
|
+
generated_site_path = temp_generated_site opts
|
24
|
+
order = [existing_subset_path, generated_site_path]
|
25
|
+
order.reverse! if opts[:merge_hack_reverse]
|
26
|
+
diff = DiffProxy.diff(order[0], order[1], :relative_to => @tmpdir)
|
27
|
+
# you could delete the tempdirs now. we will leave them there
|
28
|
+
diff
|
29
|
+
end
|
30
|
+
fail("hack failed: #{err.inspect}") unless err.empty?
|
31
|
+
$stderr.puts out # write out to err here
|
32
|
+
$stderr.puts diff.command
|
33
|
+
$stderr.puts <<-HERE.gsub(/^ +/,'')
|
34
|
+
#---------------- (above is stderr, below is stdout) ------------------
|
35
|
+
HERE
|
36
|
+
$stdout.puts diff.to_s
|
37
|
+
diff
|
38
|
+
end
|
39
|
+
private
|
40
|
+
def temp_site_subset path
|
41
|
+
subset_in_memory = dir_as_hash(path, :skip=>['output'])
|
42
|
+
@file_utils = NanDoc::Config.file_utils
|
43
|
+
subset_on_disk = @tmpdir+'/user-site'
|
44
|
+
hash_to_dir(subset_in_memory, subset_on_disk, @file_utils)
|
45
|
+
subset_on_disk
|
46
|
+
end
|
47
|
+
def temp_generated_site opts
|
48
|
+
put_it_here = @tmpdir+'/generated-site'
|
49
|
+
chops = opts.dup
|
50
|
+
chops.delete(:datasource)
|
51
|
+
@creator.run(chops, [put_it_here], :_merge=>false)
|
52
|
+
remove_output_directory(put_it_here)
|
53
|
+
put_it_here
|
54
|
+
end
|
55
|
+
def remove_output_directory put_it_here
|
56
|
+
dir = put_it_here + '/output'
|
57
|
+
fail("fail") unless File.directory?(dir)
|
58
|
+
fail("fail") unless Dir[dir+'/*'].empty?
|
59
|
+
@file_utils.remove_entry_secure(dir)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module NanDoc
|
2
|
+
module SiteMethods
|
3
|
+
|
4
|
+
def deduce_site_path_or_fail args
|
5
|
+
if args.any?
|
6
|
+
deduce_site_path_from_args args
|
7
|
+
else
|
8
|
+
deduce_site_path_from_persistent_data
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def config_path_for_site_path path
|
15
|
+
path + '/config.yaml'
|
16
|
+
end
|
17
|
+
|
18
|
+
def deduce_site_path_from_args args
|
19
|
+
if File.exist?(args.first)
|
20
|
+
path = args.first
|
21
|
+
unless path == persistent_get('last_site_path')
|
22
|
+
persistent_set('last_site_path', path)
|
23
|
+
end
|
24
|
+
path
|
25
|
+
else
|
26
|
+
task_abort <<-D.gsub(/^ */,'')
|
27
|
+
site path not found: #{args.first.inspect}
|
28
|
+
usage: #{usage}
|
29
|
+
#{invite_to_more_command_help}
|
30
|
+
D
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def deduce_site_path_from_persistent_data
|
35
|
+
if path = persistent_get('last_site_path')
|
36
|
+
if File.exist?(path)
|
37
|
+
path
|
38
|
+
else
|
39
|
+
persistent_set('last_site_path',false)
|
40
|
+
task_abort <<-D.gsub(/^ */,'')
|
41
|
+
previous site path is stale (#{path.inspect}) and no site provided
|
42
|
+
usage: #{usage}
|
43
|
+
#{invite_to_more_command_help}
|
44
|
+
D
|
45
|
+
end
|
46
|
+
else
|
47
|
+
task_abort(
|
48
|
+
'no site path provided and no site path in persistent data file '<<
|
49
|
+
"(#{NanDoc.dotfile_path})\n"<<
|
50
|
+
<<-D.gsub(/^ */,'')
|
51
|
+
usage: #{usage}
|
52
|
+
#{invite_to_more_command_help}
|
53
|
+
D
|
54
|
+
)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
#
|
59
|
+
# you just get the raw file data tree, it's not merged in with any
|
60
|
+
# DEFAULT_CONFIG stuff or anything
|
61
|
+
#
|
62
|
+
def parse_config_for_site_path path
|
63
|
+
config_path = config_path_for_site_path( path )
|
64
|
+
task_abort("config file for app not found: #{config_path}") unless
|
65
|
+
File.exist?(config_path)
|
66
|
+
YAML.load_file config_path
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,203 @@
|
|
1
|
+
module NanDoc
|
2
|
+
class StreamColorizer
|
3
|
+
module RuleList; end
|
4
|
+
module SecretParent; end
|
5
|
+
include RuleList;
|
6
|
+
def dup
|
7
|
+
other = self.class.new
|
8
|
+
other.stylesheet = stylesheet.dup
|
9
|
+
other.rule_list = rule_list.dup
|
10
|
+
other.state_set = state_set.dup
|
11
|
+
other
|
12
|
+
end
|
13
|
+
def initialize(*a, &b)
|
14
|
+
rule_list_init
|
15
|
+
@stylesheet = {}
|
16
|
+
if a.any? || block_given?
|
17
|
+
merge(*a, &b)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
attr_writer :rule_list
|
21
|
+
def filter string, out
|
22
|
+
found = rule_list.detect{ |x| x.match(string) }
|
23
|
+
use_state = found ? found.state : :plain
|
24
|
+
state = get_state_or_fail(use_state)
|
25
|
+
string = string.dup
|
26
|
+
while next_state_name = state.process(string, out)
|
27
|
+
state = get_state_or_fail(next_state_name)
|
28
|
+
end
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
def merge(&block)
|
32
|
+
yield(self) if block_given?
|
33
|
+
self
|
34
|
+
end
|
35
|
+
def spawn(*a, &b)
|
36
|
+
other = dup
|
37
|
+
other.merge(*a, &b)
|
38
|
+
other
|
39
|
+
end
|
40
|
+
attr_writer :state_set
|
41
|
+
attr_accessor :stylesheet
|
42
|
+
def stylesheet_merge other
|
43
|
+
@stylesheet.merge!(other)
|
44
|
+
end
|
45
|
+
|
46
|
+
#
|
47
|
+
# api private classes:
|
48
|
+
#
|
49
|
+
|
50
|
+
module RuleList
|
51
|
+
def rule_list_init
|
52
|
+
@rule_list = []
|
53
|
+
@state_set = {}
|
54
|
+
end
|
55
|
+
def add_regex_rule re, opts
|
56
|
+
fail("no") unless opts[:state]
|
57
|
+
@rule_list.push RegexRule.make(re, opts[:state], {})
|
58
|
+
end
|
59
|
+
def add_regex_rule_neg re, opts
|
60
|
+
fail("no") unless opts[:state]
|
61
|
+
@rule_list.push RegexRule.make(re, opts[:state], {:neg=>true})
|
62
|
+
end
|
63
|
+
def define_state name, &block
|
64
|
+
state = State.new(self, name, &block)
|
65
|
+
fail("no") if @state_set.key?(state.name)
|
66
|
+
@state_set[state.name] = state
|
67
|
+
end
|
68
|
+
def get_state_or_fail name
|
69
|
+
state = @state_set[name]
|
70
|
+
state or fail("no such state: #{name.inspect}")
|
71
|
+
state
|
72
|
+
end
|
73
|
+
attr_reader :rule_list
|
74
|
+
def when(re_or_symbol, opts=nil, &block)
|
75
|
+
if re_or_symbol.kind_of?(Regexp) && Hash===opts && ! block_given?
|
76
|
+
add_regex_rule(re_or_symbol, opts)
|
77
|
+
elsif re_or_symbol.kind_of?(Symbol) && opts.nil? && block_given?
|
78
|
+
define_state(re_or_symbol, &block)
|
79
|
+
else
|
80
|
+
fail("unrecongized signature: `#{self.class}#when("<<
|
81
|
+
"[#{re_or_symbol.class}],[#{opts.class}],[#{block.class}])")
|
82
|
+
end
|
83
|
+
end
|
84
|
+
def when_not re, opts
|
85
|
+
add_regex_rule_neg re, opts
|
86
|
+
end
|
87
|
+
attr_reader :state_set
|
88
|
+
end
|
89
|
+
class RegexRule
|
90
|
+
class << self
|
91
|
+
def make regex, state, opts
|
92
|
+
if opts[:neg]
|
93
|
+
RegexRuleNeg.new(regex, state)
|
94
|
+
else
|
95
|
+
RegexRule.new(regex, state)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
def initialize regex, state
|
100
|
+
@regex = regex
|
101
|
+
@state = state or fail('no')
|
102
|
+
end
|
103
|
+
attr_reader :regex, :state
|
104
|
+
def match str
|
105
|
+
@regex =~ str
|
106
|
+
end
|
107
|
+
end
|
108
|
+
class RegexRuleNeg < RegexRule
|
109
|
+
def match str
|
110
|
+
! super
|
111
|
+
end
|
112
|
+
end
|
113
|
+
class State
|
114
|
+
include RuleList, Treebis::Colorize, NanDoc::SecretParent
|
115
|
+
def initialize parent, name, &block
|
116
|
+
self.parent = parent
|
117
|
+
rule_list_init
|
118
|
+
fail('no') unless Symbol === name
|
119
|
+
@name = name
|
120
|
+
@style = nil
|
121
|
+
@trailing_whitespace_style = nil
|
122
|
+
block.call(self)
|
123
|
+
end
|
124
|
+
attr_accessor :name
|
125
|
+
def next_line str, alter=false
|
126
|
+
res = false
|
127
|
+
if str == ''
|
128
|
+
nil
|
129
|
+
elsif alter
|
130
|
+
if /\A([^\n]+)(?:\n?)(.*)\Z/m =~ str
|
131
|
+
res = $1
|
132
|
+
str.replace($2)
|
133
|
+
else
|
134
|
+
fail("fail: #{str.inspect}")
|
135
|
+
end
|
136
|
+
else
|
137
|
+
if /\A([^\n]+)/ =~ str
|
138
|
+
res = $1
|
139
|
+
else
|
140
|
+
fail("fail: #{str.inspect}")
|
141
|
+
end
|
142
|
+
end
|
143
|
+
res
|
144
|
+
end
|
145
|
+
def process string, out
|
146
|
+
ret = nil
|
147
|
+
while line = next_line(string)
|
148
|
+
if other = rule_list.detect{|x| x.match(string)}
|
149
|
+
next_state_name = other.state
|
150
|
+
ret = next_state_name
|
151
|
+
break
|
152
|
+
else
|
153
|
+
next_line(string, true) # alter string
|
154
|
+
use_line = nil
|
155
|
+
if @trailing_whitespace_style
|
156
|
+
/\A(|.*[^[:space:]])([[:space:]]*)\Z/ =~ line or fail('oops')
|
157
|
+
head, tail = $1, $2
|
158
|
+
colored_head = colorize(head, *colors)
|
159
|
+
use_line = colored_head.dup
|
160
|
+
unless tail.empty?
|
161
|
+
ws_style = parent.stylesheet[@trailing_whitespace_style] or
|
162
|
+
style_not_found_failure('@trailing_whitespace_style')
|
163
|
+
colored_tail = colorize(tail, *ws_style)
|
164
|
+
use_line.concat colored_tail
|
165
|
+
end
|
166
|
+
else
|
167
|
+
use_line = colorize(line, *colors)
|
168
|
+
end
|
169
|
+
out.puts use_line
|
170
|
+
end
|
171
|
+
end
|
172
|
+
ret
|
173
|
+
end
|
174
|
+
def colors
|
175
|
+
@colors ||= begin
|
176
|
+
if style.nil?
|
177
|
+
[]
|
178
|
+
else
|
179
|
+
parent.stylesheet[style] or style_not_found_failure
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
def style *a
|
184
|
+
case a.size
|
185
|
+
when 0; @style
|
186
|
+
when 1; @style = a.first
|
187
|
+
else fail('no')
|
188
|
+
end
|
189
|
+
end
|
190
|
+
def trailing_whitespace_style *a
|
191
|
+
case a.size
|
192
|
+
when 0; @trailing_whitespace_style
|
193
|
+
when 1; @trailing_whitespace_style = a.first
|
194
|
+
else fail('no')
|
195
|
+
end
|
196
|
+
end
|
197
|
+
def style_not_found_failure which = '@style'
|
198
|
+
value = instance_variable_get(which)
|
199
|
+
fail("#{which} not found: #{value.inspect}")
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|