nandoc 0.0.1

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.
Files changed (65) hide show
  1. data/README +124 -0
  2. data/Rakefile +53 -0
  3. data/bin/nandoc +6 -0
  4. data/doc/CREDITS.md +6 -0
  5. data/doc/FAQ/why-not-wiki.md +20 -0
  6. data/doc/FAQ.md +68 -0
  7. data/doc/TODOs-and-BUGs.md +15 -0
  8. data/doc/bar/baz.md +4 -0
  9. data/doc/bar/bliff.md +8 -0
  10. data/doc/foo.md +5 -0
  11. data/doc/getting-started.rb +13 -0
  12. data/doc/svg/less-fonts.svg +21 -0
  13. data/lib/nandoc/commands/create-nandoc-site.rb +225 -0
  14. data/lib/nandoc/commands/diff.rb +279 -0
  15. data/lib/nandoc/config.rb +58 -0
  16. data/lib/nandoc/cri-hacks.rb +13 -0
  17. data/lib/nandoc/data-source.rb +239 -0
  18. data/lib/nandoc/filters.rb +661 -0
  19. data/lib/nandoc/helpers/menu-bouncy.rb +109 -0
  20. data/lib/nandoc/helpers/site-map.rb +157 -0
  21. data/lib/nandoc/helpers/top-nav.rb +47 -0
  22. data/lib/nandoc/helpers.rb +42 -0
  23. data/lib/nandoc/item-class-hacks.rb +57 -0
  24. data/lib/nandoc/nandoc.persistent.json +3 -0
  25. data/lib/nandoc/parse-readme.rb +95 -0
  26. data/lib/nandoc/spec-doc/mini-test/spec-instance-methods.rb +0 -0
  27. data/lib/nandoc/spec-doc/mini-test.rb +105 -0
  28. data/lib/nandoc/spec-doc/mock-prompt.rb +121 -0
  29. data/lib/nandoc/spec-doc/support-modules.rb +158 -0
  30. data/lib/nandoc/spec-doc/test-case-agent.rb +57 -0
  31. data/lib/nandoc/spec-doc/test-framework-dispatcher.rb +15 -0
  32. data/lib/nandoc/spec-doc/test-framework-proxy.rb +78 -0
  33. data/lib/nandoc/spec-doc.rb +46 -0
  34. data/lib/nandoc/support/diff-proxy.rb +113 -0
  35. data/lib/nandoc/support/orphanage.rb +77 -0
  36. data/lib/nandoc/support/path-tardo.rb +85 -0
  37. data/lib/nandoc/support/regexp-enhance.rb +76 -0
  38. data/lib/nandoc/support/site-diff.rb +46 -0
  39. data/lib/nandoc/support/site-merge.rb +62 -0
  40. data/lib/nandoc/support/site-methods.rb +69 -0
  41. data/lib/nandoc/support/stream-colorizer.rb +203 -0
  42. data/lib/nandoc/support-modules.rb +270 -0
  43. data/lib/nandoc/test/diff-to-string.rb +251 -0
  44. data/lib/nandoc/test/minitest-extlib.rb +53 -0
  45. data/lib/nandoc/treebis/NOGIT-DOCS/NEWS.md +5 -0
  46. data/lib/nandoc/treebis/NOGIT-README.md +65 -0
  47. data/lib/nandoc/treebis/nandoc.persistent.json +3 -0
  48. data/lib/nandoc.rb +48 -0
  49. data/proto/README.md +31 -0
  50. data/proto/default/Rakefile +1 -0
  51. data/proto/default/Rules +46 -0
  52. data/proto/default/config.yaml +57 -0
  53. data/proto/default/content/css/nanoc-dist-altered.css +213 -0
  54. data/proto/default/content/css/trollop-subset.css +116 -0
  55. data/proto/default/content/js/menu-bouncy.js +126 -0
  56. data/proto/default/content/stylesheet.css.diff +20 -0
  57. data/proto/default/content/vendor/jquery-1.3.js +4241 -0
  58. data/proto/default/content/vendor/jquery.easing.1.3.js +205 -0
  59. data/proto/default/layouts/default.html +70 -0
  60. data/proto/default/lib/default.orig.rb +2 -0
  61. data/proto/default/lib/default.rb +5 -0
  62. data/proto/default/treebis-task.rb +28 -0
  63. data/proto/misc/orphan-surrogate.md +6 -0
  64. data/test/test.rb +102 -0
  65. metadata +166 -0
@@ -0,0 +1,270 @@
1
+ module NanDoc
2
+ module CliCommandHelpers
3
+ def command_name
4
+ (/::([_a-z0-9]+)\Z/i =~ self.class.to_s and base = $1) or fail('no')
5
+ base.gsub(/([a-z])([A-Z])/){ "#{$1}-#{$2}" }.downcase
6
+ end
7
+ def invite_to_more_command_help
8
+ "see `nandoc help #{command_name}` for more information."
9
+ end
10
+ def invocation_name
11
+ File.basename($PROGRAM_NAME)
12
+ end
13
+ end
14
+ module StringFormatting; end
15
+ module OptsNormalizer
16
+ def normalize_opts opts
17
+ opts = opts.dup
18
+ opts.keys.select{|x| x.to_s.index('-') }.each do |k|
19
+ opts[k.to_s.gsub('-','_').to_sym] = opts.delete(k)
20
+ end
21
+ opts
22
+ end
23
+ def unnormalize_opt_keys keys
24
+ keys.map{|x| unnormalize_opt_key(x)}
25
+ end
26
+ def unnormalize_opt_key key
27
+ "--#{key.to_s.gsub('_','-')}"
28
+ end
29
+
30
+ #
31
+ # only call this if you are like a ::Cri::Command object with
32
+ # all the nanDoc hacks. ick. This is a temprary hack. Trollop et al
33
+ # do this better.
34
+ #
35
+ def exclusive_opt_flags opts, &block
36
+ Exclusive.new(&block).parse(self, opts)
37
+ end
38
+
39
+ class Exclusive
40
+ include OptsNormalizer
41
+ def initialize &block
42
+ @exclusive_flag_keys = nil
43
+ @default_short = nil
44
+ @default_key = nil
45
+ @notice_stream = $stderr
46
+ instance_eval(&block)
47
+ fail('definition block needs at least flags()') unless
48
+ @exclusive_flag_keys
49
+ end
50
+ def flags * exclusive_flag_keys
51
+ @exclusive_flag_keys = exclusive_flag_keys
52
+ end
53
+ # params: [short_name_string] name_key
54
+ def default *a
55
+ if a.first.kind_of?(String)
56
+ @default_short = a.shift
57
+ end
58
+ if a.first.kind_of?(Symbol)
59
+ @default_key = a.shift
60
+ else
61
+ fail("bad args: #{a.first.inspect}")
62
+ end
63
+ fail("extra args: #{a.inspect}") if a.any?
64
+ end
65
+ def notice_stream mixed
66
+ @notice_stream = mixed
67
+ end
68
+ def parse cmd, opts
69
+ these = @exclusive_flag_keys & opts.keys
70
+ if these.empty? && @default_key
71
+ if @notice_stream
72
+ msg =
73
+ ["using default: "+unnormalize_opt_key(@default_key),
74
+ @default_short ? "(#{@default_short})" : nil
75
+ ].compact.join(' ')
76
+ @notice_stream.puts msg
77
+ end
78
+ these.push(@default_key)
79
+ end
80
+ if these.size > 1
81
+ flags = unnormalize_opt_keys(@exclusive_flag_keys)
82
+ cmd.task_abort <<-ABORT.gsub(/^ */,'')
83
+ #{flags.join(' and ')} are mutually exclusive.
84
+ usage: #{cmd.usage}
85
+ #{cmd.invite_to_more_command_help}
86
+ ABORT
87
+ end
88
+ these.first
89
+ end
90
+ end
91
+ class OptEnum
92
+ include OptsNormalizer, StringFormatting
93
+ def initialize(&block)
94
+ instance_eval(&block)
95
+ end
96
+ def command cmd
97
+ @command = cmd
98
+ end
99
+ def default str
100
+ @default = str
101
+ end
102
+ def name name
103
+ @name = name
104
+ end
105
+ def parse opts
106
+ found = nil
107
+ if opts.key?(@name)
108
+ v = opts[@name]
109
+ re = /\A#{Regexp.escape(v)}/
110
+ founds = @values.grep(re)
111
+ case founds.size
112
+ when 0; invalid(v)
113
+ when 1; found = founds.first
114
+ else found = founds.detect{|f| f==v} or too_many(founds)
115
+ end
116
+ elsif(@default)
117
+ found = @default
118
+ else
119
+ found = nil
120
+ end
121
+ opts[@name] = found if found # normalize short versions
122
+ found
123
+ end
124
+ def values *v
125
+ v = v.first if v.size==1 && Array === v
126
+ @values = v
127
+ end
128
+ private
129
+ def coda
130
+ "usage: #{@command.usage}\n#{@command.invite_to_more_command_help}"
131
+ end
132
+ def invalid val
133
+ @command.task_abort("invalid value #{val.inspect} for "<<
134
+ "#{long_name}. #{valid_values_are}\n#{coda}")
135
+ end
136
+ def long_name
137
+ unnormalize_opt_key(@name)
138
+ end
139
+ def too_many these
140
+ @command.task_abort("did you mean " <<
141
+ oxford_comma(these,' or ', &quoted)<<" for #{long_name}?\n#{coda}")
142
+ end
143
+ def valid_values_are
144
+ "valid values are " << oxford_comma(@values,&quoted)
145
+ end
146
+ end
147
+ end
148
+ module PathHelper
149
+ def assert_path name, *paths
150
+ paths.each do |p|
151
+ unless File.exist?(p)
152
+ task_abort("#{name} does not exist: #{p}")
153
+ end
154
+ end
155
+ end
156
+ end
157
+ module StringFormatting
158
+ def basename_no_extension str
159
+ /([^\/\.]+)(?:\.[^\.\/]+)?\Z/ =~ str ? $1 : nil
160
+ end
161
+ def indent str, indent
162
+ str.gsub(/^/, indent)
163
+ end
164
+ def no_blank_lines str
165
+ str.gsub(/\n[[:space:]]*\n/, "\n")
166
+ end
167
+ def no_leading_ws str
168
+ str.sub(/\A[[:space:]]+/, '')
169
+ end
170
+ def no_trailing_ws str
171
+ str.sub(/[[:space:]]+\Z/, '')
172
+ end
173
+ def oxford_comma items, final = ' and ', &quoter
174
+ items = items.map(&quoter) if quoter
175
+ these = []
176
+ these.push final if items.size > 1
177
+ these.concat(Array.new(items.size-2,', ')) if items.size > 2
178
+ these.reverse!
179
+ items.zip(these).flatten.compact.join
180
+ end
181
+ def quoted
182
+ proc{|x| "\"#{x}\"" }
183
+ end
184
+
185
+ #
186
+ # must respond to tab() and tabs()
187
+ # reindent a block by striping leading whitespace from lines evenly
188
+ # and then re-indenting each line according to our indent.
189
+ # this could be simpler, it has been more complicated
190
+ # we do it languidly because we can
191
+ #
192
+ def reindent h1, offset=0
193
+ indent_by = tab * (tabs+offset)
194
+ unindent_by = (/\A([[:space:]]+)/ =~ h1 && $1) or
195
+ fail('regex fail -- not sure if we need this to be so strict')
196
+ h2 = no_blank_lines(h1) # careful. will mess up with <pre> etc
197
+ return h2 if unindent_by == indent_by
198
+ h3 = unindent(h2, unindent_by)
199
+ h4 = indent(h3, indent_by)
200
+ h4
201
+ end
202
+
203
+ def unindent str, by
204
+ str.gsub(/^#{Regexp.escape(by)}/, '')
205
+ end
206
+ end
207
+ module SecretParent
208
+ #
209
+ # set parent attribute without it showing up in inspect() dumps
210
+ #
211
+ def parent= mixed
212
+ fail("no clear_parent() available yet.") unless mixed
213
+ @has_parent = !! mixed
214
+ class << self; self end.send(:define_method, :parent){mixed}
215
+ mixed # maybe chain assignmnet of 1 parent to several cx at once
216
+ end
217
+ def parent?
218
+ instance_variable_defined?('@has_parent') && @has_parent # no warnings
219
+ end
220
+ def parent
221
+ nil
222
+ end
223
+ end
224
+ module SharedAttrReader
225
+ #
226
+ # this is a specialized form of delegator pattern: let one object
227
+ # use the responses from another object for a set of accessors
228
+ #
229
+ def shared_attr_reader *list
230
+ fail('no inehiritance yet') if method_defined?(:shared=)
231
+ sm = Module.new
232
+ name = self.to_s+'::SharedAttrReaders'
233
+ sing = class << sm; self end
234
+ sing.send(:define_method, :name){name}
235
+ sing.send(:alias_method, :inspect, :name)
236
+ list.each do |attrib|
237
+ sm.send(:define_method, attrib){ shared.send(attrib) }
238
+ end
239
+ fail('no') if method_defined?(:shared)
240
+ define_method(:shared){ self }
241
+ define_method(:shared=) do |source|
242
+ sing = class << self; self end
243
+ sing.send(:define_method, :shared){ source }
244
+ sing.send(:include, sm) # wow cool that this works w/o having
245
+ # to Module#undef_method
246
+ source
247
+ end
248
+ nil
249
+ end
250
+ end
251
+ module TaskCommon
252
+ def task_abort msg
253
+ if msg.index("for more info") # not mr. right, mr. right now
254
+ tail = ''
255
+ else
256
+ last = msg[-1].chr
257
+ tail = ".?!".index(last) ? ' ' : ("\n"==last ? '' : '. ')
258
+ tail << 'Aborting.'
259
+ end
260
+ $stderr.puts "nanDoc: #{msg}#{tail}"
261
+ exit 1
262
+ end
263
+ end
264
+ module CliCommandHelpers
265
+ include OptsNormalizer, TaskCommon, PathHelper
266
+ end
267
+ module PathHelper
268
+ include TaskCommon
269
+ end
270
+ end
@@ -0,0 +1,251 @@
1
+ require 'stringio'
2
+
3
+ ##
4
+ # turn the output of Diff::LCS.diff into a string similar
5
+ # to what would be retured by `diff`, optionally make it looks
6
+ # *sorta* like colorized output from git-diff
7
+ #
8
+ # @todo move this to minitest branch
9
+ # @todo this gives different results than diff for some stuff!!??
10
+ #
11
+ # poor man's diff:
12
+ # file_a, file_b = ARGV.shift(2)
13
+ # puts DiffToString.files_diff(file_a, file_b)
14
+ #
15
+ #
16
+ class DiffToString
17
+ module Style
18
+ Codes = {:red=>'31', :green=>'32', :bold=>'1', :red_bg=>'41',
19
+ :magenta => '35'
20
+ }
21
+ def stylize str, *codes
22
+ if 1 == codes.size
23
+ if codes.first.nil?
24
+ return str
25
+ elsif codes.first.kind_of?(Array)
26
+ codes = codes.first
27
+ end
28
+ end
29
+ codes = codes.map{|c| Codes[c]}
30
+ "\033[#{codes * ';'}m#{str}\033[0m";
31
+ end
32
+ end
33
+ include Style
34
+
35
+ class << self
36
+ # these are just convenience wrappers for instance methods
37
+ %w(diff files_diff strings_diff gitlike!).each do |meth|
38
+ define_method(meth){|*a| new.send(meth,*a) }
39
+ end
40
+ end
41
+ def initialize
42
+ @add_style = nil
43
+ @add_header = '%sa%s'
44
+ @change_header = '%sc%s'
45
+ @context = nil
46
+ @del_header = '%sd%s'
47
+ @del_style = nil
48
+ @last_range = nil
49
+ @left = '<'
50
+ @line_no_style = nil
51
+ @right = '>'
52
+ @separator_line = '---'
53
+ @trailing_whitespace_style = nil
54
+ end
55
+ attr_accessor :arr1, :arr2 # this is awful bleeding
56
+ def context= mixed
57
+ fail("no #{mixed.inspect}") unless mixed.kind_of?(Fixnum) && mixed >= 0
58
+ @context = mixed == 0 ? nil : mixed
59
+ end
60
+ def gitlike!
61
+ common_header = '@@ -%s, +%s @@'
62
+ @add_header = common_header
63
+ @add_style = [:bold, :green]
64
+ @change_header = common_header
65
+ @del_style = [:bold, :red]
66
+ @del_header = common_header
67
+ @header_style = [:bold, :magenta]
68
+ @left = '-'
69
+ @right = '+'
70
+ @separator_line = nil
71
+ @trailing_whitespace_style = [:red_bg]
72
+ self
73
+ end
74
+ def arrays_diff arr1, arr2, opts={}
75
+ diff = Diff::LCS.diff(arr1, arr2)
76
+ @arr1, @arr2 = arr1, arr2
77
+ consume_opts_for_diff(opts)
78
+ diff_to_str diff, opts
79
+ end
80
+ def diff mixed1, mixed2, opts={}
81
+ case (x=[mixed1.class, mixed2.class])
82
+ when [Array,Array]; arrays_diff(mixed1,mixed2,opts)
83
+ when [String,String]; strings_diff(mixed1,mixed2,opts)
84
+ else "no diff strategy for #{x.inspect}"
85
+ end
86
+ end
87
+ def files_diff a, b, opts={:sep=>"\n"}
88
+ str1 = File.read(a)
89
+ str2 = File.read(b)
90
+ strings_diff(str1, str2, opts)
91
+ end
92
+ def strings_diff a, b, opts={}
93
+ opts = opts.merge(:sep=>"\n")
94
+ arr1 = str_to_arr a, opts[:sep]
95
+ arr2 = str_to_arr b, opts[:sep]
96
+ arrays_diff(arr1, arr2, opts)
97
+ end
98
+ def str_to_arr str, sep
99
+ str.split(sep, -1)
100
+ end
101
+ def diff_to_str diff, opts
102
+ consume_opts_for_diff opts
103
+ @out = StringIO.new
104
+ @offset_offset = -1
105
+ diff.each do |chunk|
106
+ context_pre(chunk) if @context
107
+ dels = []
108
+ adds = []
109
+ start_add = last_add = start_del = last_del = nil
110
+ chunk.each do |change|
111
+ case change.action
112
+ when '+'
113
+ start_add ||= change.position + 1
114
+ last_add = change.position + 1
115
+ adds.push change.element
116
+ when '-'
117
+ start_del ||= change.position + 1
118
+ last_del = change.position + 1
119
+ dels.push change.element
120
+ else
121
+ fail("no: #{change.action}")
122
+ end
123
+ end
124
+ if adds.any? && dels.any?
125
+ puts_change_header start_del, last_del, start_add, last_add
126
+ elsif adds.any?
127
+ puts_add_header start_add, last_add
128
+ else
129
+ puts_del_header start_del, last_del
130
+ end
131
+ @offset_offset -= ( dels.size - adds.size )
132
+ dels.each do |del|
133
+ puts_del "#{@left} #{del}"
134
+ end
135
+ if adds.any? && dels.any?
136
+ puts_sep
137
+ end
138
+ adds.each do |add|
139
+ puts_add "#{@right} #{add}"
140
+ end
141
+ context_post(chunk) if @context
142
+ end
143
+ @out.rewind
144
+ @out.read
145
+ end
146
+ private
147
+ def consume_opts_for_diff opts
148
+ if opts[:colors]
149
+ opts.delete[:colors]
150
+ gitlike!
151
+ end
152
+ if opts[:context]
153
+ self.context = opts.delete(:context)
154
+ end
155
+ end
156
+ def context_pre chunk
157
+ pos = chunk.first.position - 1
158
+ puts_range_safe pos - @context, pos
159
+ end
160
+ def context_post chunk
161
+ pos = chunk.last.position + 1
162
+ puts_range_safe pos, pos + @context
163
+ end
164
+ def other_offset start
165
+ start + @offset_offset
166
+ end
167
+ def puts_del str
168
+ puts_change str, @del_style
169
+ end
170
+ def puts_add str
171
+ puts_change str, @add_style
172
+ end
173
+ def puts_add_header start_add, last_add
174
+ str = @add_header % [other_offset(start_add), range(start_add,last_add)]
175
+ @out.puts(stylize(str, @header_style))
176
+ end
177
+ def puts_change str, style
178
+ # separate string into three parts! main string,
179
+ # trailing non-newline whitespace, and trailing newlines
180
+ # we want to highlite the trailing whitespace, but if we are
181
+ # colorizing it we need to exclude the final trailing newlines
182
+ # for puts to work correctly
183
+ if /^(.*[^\s]|)([\t ]*)([\n]*)$/ =~ str
184
+ main_str, ws_str, nl_str = $1, $2, $3
185
+ @out.print(stylize(main_str, style))
186
+ @out.print(stylize(ws_str, @trailing_whitespace_style))
187
+ @out.puts(nl_str)
188
+ else
189
+ # hopefully regex never fails but it might
190
+ @out.puts(stylize(str, style))
191
+ end
192
+ end
193
+ def puts_change_header start_del, last_del, start_add, last_add
194
+ str = @change_header %
195
+ [range(start_del,last_del), range(start_add,last_add)]
196
+ @out.puts(stylize(str, @header_style))
197
+ end
198
+ def puts_del_header start_del, last_del
199
+ str = @del_header % [range(start_del,last_del), other_offset(start_del)]
200
+ @out.puts(stylize(str, @header_style))
201
+ end
202
+ def puts_range_safe start, final
203
+ start = [start, 0].max
204
+ final = [@arr1.size-1, final].min
205
+ if @last_range
206
+ start = [@last_range[1]+1, start].max
207
+ # assume sequential for now! no need to check about previous
208
+ # ones in front of us
209
+ end
210
+ return if start >= final
211
+ @last_range = [start, final]
212
+ @out.puts @arr1[start..final].map{|x| " #{x}"}
213
+ # @todo i don't know if i'm reading the chunks right
214
+ end
215
+ def puts_sep
216
+ if @separator_line
217
+ @out.puts(@separator_line)
218
+ end
219
+ end
220
+ def range min, max
221
+ if min == max
222
+ min
223
+ else
224
+ "#{min},#{max}"
225
+ end
226
+ end
227
+ end
228
+
229
+ if __FILE__ == $PROGRAM_NAME
230
+ require 'test/unit'
231
+ require 'test/unit/ui/console/testrunner'
232
+ class DiffToString::TestCase < Test::Unit::TestCase
233
+ def test_context
234
+ before = <<-B
235
+ alpha
236
+ beta
237
+ gamma
238
+ tau
239
+ B
240
+ after = <<-A
241
+ alpha
242
+ gamma
243
+ zeta
244
+ tau
245
+ A
246
+ puts DiffToString.diff(before.split("\n"), after.split("\n"),
247
+ :colors=>true, :context=>3)
248
+ end
249
+ end
250
+ Test::Unit::UI::Console::TestRunner.run(DiffToString::TestCase)
251
+ end
@@ -0,0 +1,53 @@
1
+ require 'diff/lcs'
2
+ require(File.dirname(__FILE__)+'/diff-to-string.rb')
3
+
4
+ module MiniTest
5
+ module Assertions
6
+
7
+ ##
8
+ # Fails unless <tt>exp == act</tt>.
9
+ # On failure use diff to show the diff, if +exp+
10
+ # and +act+ are of the same class and
11
+ #
12
+
13
+ def assert_no_diff exp, act, msg=nil, opts={}
14
+ if opts.kind_of?(String)
15
+ opts = {:sep=>opts}
16
+ end
17
+ opts = {:sep=>"\n"}.merge(opts)
18
+ msg = message(msg) do
19
+ exp_kind, act_kind = [exp,act].map do |x|
20
+ [String, Array].detect{|c| x.kind_of?(c)}
21
+ end
22
+ if exp_kind != act_kind
23
+ "Expecting #{exp_kind.inspect} had #{act_kind.inspect}"
24
+ elsif exp_kind.nil?
25
+ "Will only do diff for strings and arrays, not #{exp.class}"
26
+ else
27
+ differ = DiffToString.gitlike!
28
+ if exp_kind == String
29
+ use_exp = exp.split(opts[:sep], -1)
30
+ use_act = act.split(opts[:sep], -1)
31
+ else
32
+ use_exp = exp
33
+ use_act = act
34
+ end
35
+ diff = Diff::LCS.diff(use_exp, use_act)
36
+ if diff.empty?
37
+ fail("test test fail -- never expecting empty diff here")
38
+ else
39
+ differ.arr1 = use_exp
40
+ differ.arr2 = use_act # awful
41
+ differ.diff_to_str(diff, :context=>3)
42
+ end
43
+ end
44
+ end
45
+ if re = opts[:ignoring]
46
+ exp, act = [exp, act].map do |str|
47
+ str.kind_of?(String) ? str.gsub(re, re.source) : str
48
+ end
49
+ end
50
+ assert(exp == act, msg)
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,5 @@
1
+ # treebis news
2
+
3
+ ## 0.0.0 (2010-99-99)
4
+
5
+ * born but not a birther
@@ -0,0 +1,65 @@
1
+ ## treebis
2
+
3
+ ### in short,
4
+ Treebis is a minimal (small) task utility written in ruby designed expressly for wrapping common actions for moving, copying and altering filetrees. It's geared towards things like generators. Its look is comparable to a Rake task. Its effect is comparable to a shell script composed of mkdir, mv, cp commands etc.
5
+
6
+ This document is overkill. Treebis is underkill.
7
+
8
+ ### it is:
9
+ - task wrapper for external commands that make filetrees, e.g.
10
+ - maybe the generators in things like rails, ramaze, nandoc
11
+ - copies filetrees to filetrees
12
+ - removes filetrees from filetrees
13
+ - applies diffs to filetrees
14
+ - different ways to represent trees and diffs - heredocs, diffs, filesystem.
15
+ - under 500 lines of code (?) (~300 SLOC ATTOTW)
16
+ - near 100% test coverage (?)
17
+
18
+ ### it is not:
19
+ - a vcs or vcs wrapper (version control system)
20
+ - atomic
21
+ - a replacement for the heavy hitters used by web frameworks
22
+ - Safe. Little sanity checking and error checking is done. At present it
23
+ it is mostly a wrapper around FileUtils and patch. If you refer to files
24
+ that aren't there or try to read/move/remove files you don't have the
25
+ permissions to do so with, you will see the errors as you would from
26
+ FileUtils.
27
+
28
+ ### faq
29
+
30
+ #### Q: why use it?
31
+
32
+ #### A:
33
+ <p class='ans'>Because you want a consistent way to wrap these common tasks that doesn't explicitly rely on shelling out to the underlying system, or other hodgepodges. (also see 'why did you make this?')
34
+ </p>
35
+
36
+ #### Q: why not use it?
37
+
38
+ #### A:
39
+ Because it doesn't do what you want or it does what you do not want.
40
+
41
+ #### Q: why is it named "Treebis?"
42
+
43
+ #### A:
44
+ because it rhymes with "Jeebus."
45
+
46
+ #### Q: why did you make this?
47
+
48
+ #### A:
49
+ by the third or fourth time i found myself re-writing this same kind of thing for different projects (or bleeding from its absence), i decided to abstract it. It's more readable than a bunch of FileUtils statements, it's more portable than a bunch of bash scripts (sorta), it's divorced from any heavy (or light) web frameworks, and it paves the way for possible future enhancements like atomicitiy and units of work; and wouldn't it be nice if every generator of every project used the same library?
50
+
51
+ ### requirements
52
+ - ruby 1.8.7
53
+ - GNU patch 2.5.8 (if the diff-patching functionality is to be used)
54
+ (most versions of patch will likely work; it uses unified diffs.)
55
+
56
+ ### installation
57
+ @todo
58
+
59
+ ### usage
60
+ @todo
61
+
62
+ ### future unfulfilled promises made today:
63
+ - dry run
64
+ - erb
65
+ - two-pass units of work !!??
@@ -0,0 +1,3 @@
1
+ {
2
+ "tmpdir": "/var/folders/Uc/UcTP6K3aF5O604wVlmM89E+++TQ/-Tmp-/treebis"
3
+ }
data/lib/nandoc.rb ADDED
@@ -0,0 +1,48 @@
1
+ # this kind of sucks but for a wicked hack to work with symlinks
2
+ # we have to wrap this sucker.
3
+
4
+ unless Object.const_defined?('NanDoc')
5
+
6
+ require 'nanoc3'
7
+ require 'nanoc3/cli'
8
+
9
+ module NanDoc
10
+ #
11
+ # i make the D big so i can see it
12
+ # i move my head away from the microphone when i breathe
13
+ #
14
+ Root = File.expand_path('../..',__FILE__)
15
+ end
16
+
17
+ me = File.dirname(__FILE__)+'/nandoc'
18
+
19
+ # order is important:
20
+ require me + '/support-modules.rb'
21
+ require 'treebis' # gem
22
+ require me + '/config.rb'
23
+
24
+ module NanDoc
25
+ Treebis::PersistentDotfile.extend_to(self,
26
+ './nandoc.persistent.json',
27
+ :file_utils => Config.file_utils
28
+ )
29
+ end
30
+
31
+ # order is not important: (alphabetical:)
32
+ require me + '/commands/create-nandoc-site.rb'
33
+ require me + '/commands/diff.rb'
34
+ require me + '/cri-hacks.rb'
35
+ require me + '/data-source.rb'
36
+ require me + '/filters.rb'
37
+ require me + '/helpers.rb'
38
+ require me + '/item-class-hacks.rb'
39
+
40
+ Nanoc3::DataSource.register ::NanDoc::DataSource, :nandoc
41
+ Nanoc3::Filter.register ::NanDoc::Filters::General, :nandoc
42
+
43
+ shared_base = Nanoc3::CLI::Base.shared_base
44
+ shared_base.remove_command Nanoc3::CLI::Commands::CreateSite
45
+ shared_base.add_command NanDoc::CreateNanDocSite.new
46
+ shared_base.add_command NanDoc::Commands::Diff.new
47
+
48
+ end