nandoc 0.0.1

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