leg 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/leg +9 -0
- data/lib/snaptoken.rb +24 -0
- data/lib/snaptoken/cli.rb +61 -0
- data/lib/snaptoken/commands.rb +13 -0
- data/lib/snaptoken/commands/amend.rb +27 -0
- data/lib/snaptoken/commands/base_command.rb +92 -0
- data/lib/snaptoken/commands/build.rb +107 -0
- data/lib/snaptoken/commands/commit.rb +27 -0
- data/lib/snaptoken/commands/help.rb +38 -0
- data/lib/snaptoken/commands/resolve.rb +27 -0
- data/lib/snaptoken/commands/status.rb +21 -0
- data/lib/snaptoken/commands/step.rb +35 -0
- data/lib/snaptoken/default_templates.rb +287 -0
- data/lib/snaptoken/diff.rb +180 -0
- data/lib/snaptoken/diff_line.rb +54 -0
- data/lib/snaptoken/diff_transformers.rb +9 -0
- data/lib/snaptoken/diff_transformers/base_transformer.rb +9 -0
- data/lib/snaptoken/diff_transformers/fold_sections.rb +85 -0
- data/lib/snaptoken/diff_transformers/omit_adjacent_removals.rb +28 -0
- data/lib/snaptoken/diff_transformers/trim_blank_lines.rb +21 -0
- data/lib/snaptoken/markdown.rb +18 -0
- data/lib/snaptoken/page.rb +64 -0
- data/lib/snaptoken/representations.rb +8 -0
- data/lib/snaptoken/representations/base_representation.rb +38 -0
- data/lib/snaptoken/representations/git.rb +262 -0
- data/lib/snaptoken/representations/litdiff.rb +81 -0
- data/lib/snaptoken/step.rb +27 -0
- data/lib/snaptoken/template.rb +53 -0
- data/lib/snaptoken/tutorial.rb +64 -0
- metadata +115 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 286e3954f7bbf9670f82bd13781641352b4ea836
|
4
|
+
data.tar.gz: 7072bb1eb4f69782adf5b62fdf31bbd52b583f55
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8098a085df44829793ff34b0c2a8d4ba53aaf7a2bee1c1450e4e760ad7947baef9ec99120e5664dd4722ee988863d42169a6aa8c3add8d0f7170ca5b2ee62843
|
7
|
+
data.tar.gz: 77a5adb334ce1d0ba9fd2582a7d169e2cfee7155b34b148033189bbaa037fe5ed244bb940d2b4a8b7b5d006779e6d36a6693777b7525ebea50217db909f0c8e8
|
data/bin/leg
ADDED
data/lib/snaptoken.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'optparse'
|
4
|
+
require 'redcarpet'
|
5
|
+
require 'rouge'
|
6
|
+
require 'rouge/plugins/redcarpet'
|
7
|
+
require 'rugged'
|
8
|
+
require 'yaml'
|
9
|
+
|
10
|
+
module Snaptoken
|
11
|
+
end
|
12
|
+
|
13
|
+
require 'snaptoken/cli'
|
14
|
+
require 'snaptoken/commands'
|
15
|
+
require 'snaptoken/default_templates'
|
16
|
+
require 'snaptoken/diff'
|
17
|
+
require 'snaptoken/diff_line'
|
18
|
+
require 'snaptoken/diff_transformers'
|
19
|
+
require 'snaptoken/markdown'
|
20
|
+
require 'snaptoken/page'
|
21
|
+
require 'snaptoken/representations'
|
22
|
+
require 'snaptoken/step'
|
23
|
+
require 'snaptoken/template'
|
24
|
+
require 'snaptoken/tutorial'
|
@@ -0,0 +1,61 @@
|
|
1
|
+
class Snaptoken::CLI
|
2
|
+
CONFIG_FILE = "leg.yml"
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
initial_dir = FileUtils.pwd
|
6
|
+
|
7
|
+
@tutorial = nil
|
8
|
+
last_dir = nil
|
9
|
+
while FileUtils.pwd != last_dir
|
10
|
+
if File.exist?(CONFIG_FILE)
|
11
|
+
config = YAML.load_file(CONFIG_FILE)
|
12
|
+
if config == false
|
13
|
+
puts "Error: Invalid config file."
|
14
|
+
exit!
|
15
|
+
end
|
16
|
+
config = {} unless config.is_a?(Hash)
|
17
|
+
config[:path] = FileUtils.pwd
|
18
|
+
config = symbolize_keys(config)
|
19
|
+
@tutorial = Snaptoken::Tutorial.new(config)
|
20
|
+
break
|
21
|
+
end
|
22
|
+
|
23
|
+
last_dir = FileUtils.pwd
|
24
|
+
FileUtils.cd('..')
|
25
|
+
end
|
26
|
+
|
27
|
+
FileUtils.cd(initial_dir)
|
28
|
+
end
|
29
|
+
|
30
|
+
def run(args)
|
31
|
+
args = ["help"] if args.empty?
|
32
|
+
cmd_name = args.shift.downcase
|
33
|
+
|
34
|
+
if cmd_name =~ /\A\d+\z/
|
35
|
+
args.unshift(cmd_name)
|
36
|
+
cmd_name = "step"
|
37
|
+
end
|
38
|
+
|
39
|
+
if cmd = Snaptoken::Commands::LIST.find { |cmd| cmd.name == cmd_name }
|
40
|
+
cmd.new(args, @tutorial).run
|
41
|
+
else
|
42
|
+
puts "There is no '#{cmd_name}' command. Run `leg help` for help."
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def symbolize_keys(value)
|
49
|
+
case value
|
50
|
+
when Hash
|
51
|
+
value.map do |k, v|
|
52
|
+
[k.to_sym, symbolize_keys(v)]
|
53
|
+
end.to_h
|
54
|
+
when Array
|
55
|
+
value.map { |v| symbolize_keys(v) }
|
56
|
+
else
|
57
|
+
value
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Snaptoken::Commands
|
2
|
+
LIST = []
|
3
|
+
end
|
4
|
+
|
5
|
+
require 'snaptoken/commands/base_command'
|
6
|
+
|
7
|
+
require 'snaptoken/commands/build'
|
8
|
+
require 'snaptoken/commands/status'
|
9
|
+
require 'snaptoken/commands/commit'
|
10
|
+
require 'snaptoken/commands/amend'
|
11
|
+
require 'snaptoken/commands/resolve'
|
12
|
+
require 'snaptoken/commands/step'
|
13
|
+
require 'snaptoken/commands/help'
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class Snaptoken::Commands::Amend < Snaptoken::Commands::BaseCommand
|
2
|
+
def self.name
|
3
|
+
"amend"
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.summary
|
7
|
+
"Modify a step."
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.usage
|
11
|
+
""
|
12
|
+
end
|
13
|
+
|
14
|
+
def setopts!(o)
|
15
|
+
end
|
16
|
+
|
17
|
+
def run
|
18
|
+
needs! :config, :repo
|
19
|
+
|
20
|
+
if @git.commit!(amend: true)
|
21
|
+
git_to_litdiff!
|
22
|
+
puts "Success!"
|
23
|
+
else
|
24
|
+
puts "Looks like you've got a conflict to resolve!"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
class Snaptoken::Commands::BaseCommand
|
2
|
+
attr_reader :config
|
3
|
+
|
4
|
+
def initialize(args, tutorial)
|
5
|
+
@args = args
|
6
|
+
@tutorial = tutorial
|
7
|
+
@git = Snaptoken::Representations::Git.new(@tutorial)
|
8
|
+
@litdiff = Snaptoken::Representations::Litdiff.new(@tutorial)
|
9
|
+
parseopts!
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.name; raise NotImplementedError; end
|
13
|
+
def self.summary; raise NotImplementedError; end
|
14
|
+
def setopts!(o); raise NotImplementedError; end
|
15
|
+
def run; raise NotImplementedError; end
|
16
|
+
|
17
|
+
def self.inherited(subclass)
|
18
|
+
Snaptoken::Commands::LIST << subclass
|
19
|
+
end
|
20
|
+
|
21
|
+
def parseopts!
|
22
|
+
parser = OptionParser.new do |o|
|
23
|
+
o.banner = "Usage: leg #{self.class.name} #{self.class.usage}"
|
24
|
+
self.class.summary.split("\n").each do |line|
|
25
|
+
o.separator " #{line}"
|
26
|
+
end
|
27
|
+
o.separator ""
|
28
|
+
o.separator "Options:"
|
29
|
+
setopts!(o)
|
30
|
+
o.on_tail("-h", "--help", "Show this message") do
|
31
|
+
puts o
|
32
|
+
exit
|
33
|
+
end
|
34
|
+
end
|
35
|
+
@opts = {}
|
36
|
+
parser.parse!(@args)
|
37
|
+
rescue OptionParser::InvalidOption, OptionParser::InvalidArgument => e
|
38
|
+
puts "#{e.message}"
|
39
|
+
puts
|
40
|
+
parser.parse("--help")
|
41
|
+
end
|
42
|
+
|
43
|
+
def needs!(*whats)
|
44
|
+
whats.each do |what|
|
45
|
+
case what
|
46
|
+
when :config
|
47
|
+
if @tutorial.nil?
|
48
|
+
puts "Error: You are not in a leg working directory."
|
49
|
+
exit 1
|
50
|
+
end
|
51
|
+
when :repo
|
52
|
+
if @litdiff.modified? and @git.modified?
|
53
|
+
puts "Error: doc/ and .leg/repo have diverged!"
|
54
|
+
exit 1
|
55
|
+
elsif @litdiff.modified? or !@git.exists?
|
56
|
+
litdiff_to_git!
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def git_to_litdiff!
|
63
|
+
@git.load! do |step_num|
|
64
|
+
print "\r\e[K[repo/ -> Tutorial] Step #{step_num}" unless @opts[:quiet]
|
65
|
+
end
|
66
|
+
puts unless @opts[:quiet]
|
67
|
+
|
68
|
+
num_steps = @tutorial.num_steps
|
69
|
+
@litdiff.save! do |step_num|
|
70
|
+
print "\r\e[K[Tutorial -> doc/] Step #{step_num}/#{num_steps}" unless @opts[:quiet]
|
71
|
+
end
|
72
|
+
puts unless @opts[:quiet]
|
73
|
+
|
74
|
+
@tutorial.synced!
|
75
|
+
end
|
76
|
+
|
77
|
+
def litdiff_to_git!
|
78
|
+
@litdiff.load! do |step_num|
|
79
|
+
print "\r\e[K[doc/ -> Tutorial] Step #{step_num}" unless @opts[:quiet]
|
80
|
+
end
|
81
|
+
puts unless @opts[:quiet]
|
82
|
+
|
83
|
+
num_steps = @tutorial.num_steps
|
84
|
+
@git.save! do |step_num|
|
85
|
+
print "\r\e[K[Tutorial -> repo/] Step #{step_num}/#{num_steps}" unless @opts[:quiet]
|
86
|
+
end
|
87
|
+
puts unless @opts[:quiet]
|
88
|
+
|
89
|
+
@tutorial.synced!
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
@@ -0,0 +1,107 @@
|
|
1
|
+
class Snaptoken::Commands::Build < Snaptoken::Commands::BaseCommand
|
2
|
+
def self.name
|
3
|
+
"build"
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.summary
|
7
|
+
"Render repo/ into an HTML or Markdown book."
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.usage
|
11
|
+
"[-q]"
|
12
|
+
end
|
13
|
+
|
14
|
+
def setopts!(o)
|
15
|
+
o.on("-q", "--quiet", "Don't output progress") do |q|
|
16
|
+
@opts[:quiet] = q
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def run
|
21
|
+
args = @opts[:quiet] ? ["--quiet"] : []
|
22
|
+
|
23
|
+
needs! :config, :repo
|
24
|
+
|
25
|
+
@git.load!(full_diffs: true, diffs_ignore_whitespace: true) do |step_num|
|
26
|
+
print "\r\e[K[repo/ -> Tutorial] Step #{step_num}" unless @opts[:quiet]
|
27
|
+
end
|
28
|
+
puts unless @opts[:quiet]
|
29
|
+
|
30
|
+
num_steps = @tutorial.num_steps
|
31
|
+
|
32
|
+
if @tutorial.config[:diff_transformers]
|
33
|
+
transformers = @tutorial.config[:diff_transformers].map do |transformer_config|
|
34
|
+
if transformer_config.is_a? String
|
35
|
+
transformer = transformer_config
|
36
|
+
options = {}
|
37
|
+
else
|
38
|
+
transformer = transformer_config.keys.first
|
39
|
+
options = transformer_config.values.first
|
40
|
+
end
|
41
|
+
Snaptoken::DiffTransformers.const_get(transformer).new(options)
|
42
|
+
end
|
43
|
+
|
44
|
+
@tutorial.transform_diffs(transformers) do |step_num|
|
45
|
+
print "\r\e[K[Transform diffs] Step #{step_num}/#{num_steps}" unless @opts[:quiet]
|
46
|
+
end
|
47
|
+
puts unless @opts[:quiet]
|
48
|
+
end
|
49
|
+
|
50
|
+
FileUtils.mkdir_p(File.join(@tutorial.config[:path], "template"))
|
51
|
+
FileUtils.cd(File.join(@tutorial.config[:path], "template")) do
|
52
|
+
FileUtils.rm_rf("../build")
|
53
|
+
FileUtils.mkdir_p("../build/html")
|
54
|
+
FileUtils.mkdir_p("../build/html-offline")
|
55
|
+
|
56
|
+
include_default_css = true
|
57
|
+
if File.exist?("page.html.erb")
|
58
|
+
@tutorial.page_template = File.read("page.html.erb")
|
59
|
+
include_default_css = false
|
60
|
+
end
|
61
|
+
|
62
|
+
if File.exist?("step.html.erb")
|
63
|
+
@tutorial.step_template = File.read("step.html.erb")
|
64
|
+
end
|
65
|
+
@tutorial.step_template.gsub!(/\\\s*/, "")
|
66
|
+
|
67
|
+
@tutorial.pages.each do |page|
|
68
|
+
print "\r\e[K[Tutorial -> build/] Page #{page.filename}" unless @opts[:quiet]
|
69
|
+
|
70
|
+
html = page.to_html(@tutorial, false)
|
71
|
+
File.write("../build/html/#{page.filename}.html", html)
|
72
|
+
|
73
|
+
offline_html = page.to_html(@tutorial, true)
|
74
|
+
File.write("../build/html-offline/#{page.filename}.html", offline_html)
|
75
|
+
end
|
76
|
+
puts unless @opts[:quiet]
|
77
|
+
|
78
|
+
Dir["*"].each do |f|
|
79
|
+
name = File.basename(f)
|
80
|
+
|
81
|
+
next if %w(page.html.erb step.html.erb).include? name
|
82
|
+
next if name.start_with? "_"
|
83
|
+
|
84
|
+
# XXX: currently only processes top-level ERB template files.
|
85
|
+
if name.end_with? ".erb"
|
86
|
+
output = Snaptoken::Template.new(File.read(f), @tutorial, offline: false).render_template
|
87
|
+
File.write("../build/html/#{name[0..-5]}", output)
|
88
|
+
|
89
|
+
output = Snaptoken::Template.new(File.read(f), @tutorial, offline: true).render_template
|
90
|
+
File.write("../build/html-offline/#{name[0..-5]}", output)
|
91
|
+
else
|
92
|
+
FileUtils.cp_r(f, "../build/html/#{name}")
|
93
|
+
FileUtils.cp_r(f, "../build/html-offline/#{name}")
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
if include_default_css && !File.exist?("../build/html/style.css")
|
98
|
+
output = Snaptoken::Template.new(Snaptoken::DefaultTemplates::CSS, @tutorial, offline: false).render_template
|
99
|
+
File.write("../build/html/style.css", output)
|
100
|
+
end
|
101
|
+
if include_default_css && !File.exist?("../build/html-offline/style.css")
|
102
|
+
output = Snaptoken::Template.new(Snaptoken::DefaultTemplates::CSS, @tutorial, offline: true).render_template
|
103
|
+
File.write("../build/html-offline/style.css", output)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class Snaptoken::Commands::Commit < Snaptoken::Commands::BaseCommand
|
2
|
+
def self.name
|
3
|
+
"commit"
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.summary
|
7
|
+
"Append or insert a new step."
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.usage
|
11
|
+
""
|
12
|
+
end
|
13
|
+
|
14
|
+
def setopts!(o)
|
15
|
+
end
|
16
|
+
|
17
|
+
def run
|
18
|
+
needs! :config, :repo
|
19
|
+
|
20
|
+
if @git.commit!
|
21
|
+
git_to_litdiff!
|
22
|
+
puts "Success!"
|
23
|
+
else
|
24
|
+
puts "Looks like you've got a conflict to resolve!"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class Snaptoken::Commands::Help < Snaptoken::Commands::BaseCommand
|
2
|
+
def self.name
|
3
|
+
"help"
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.summary
|
7
|
+
"Print out list of commands, or get help\n" +
|
8
|
+
"on a specific command."
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.usage
|
12
|
+
"[<command>]"
|
13
|
+
end
|
14
|
+
|
15
|
+
def setopts!(o)
|
16
|
+
end
|
17
|
+
|
18
|
+
def run
|
19
|
+
if @args.empty?
|
20
|
+
puts "Usage: leg <command> [args...]"
|
21
|
+
puts
|
22
|
+
puts "Commands:"
|
23
|
+
Snaptoken::Commands::LIST.each do |cmd|
|
24
|
+
puts " #{cmd.name} #{cmd.usage}"
|
25
|
+
cmd.summary.split("\n").each do |line|
|
26
|
+
puts " #{line}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
puts
|
30
|
+
puts "For more help on a specific command, run `leg help <command>`."
|
31
|
+
elsif cmd = Snaptoken::Commands::LIST.find { |cmd| cmd.name == @args.first }
|
32
|
+
cmd.new(["--help"], @tutorial)
|
33
|
+
else
|
34
|
+
puts "There is no '#{@args.first}' command."
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class Snaptoken::Commands::Resolve < Snaptoken::Commands::BaseCommand
|
2
|
+
def self.name
|
3
|
+
"resolve"
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.summary
|
7
|
+
"Continue rewriting steps after resolving a merge conflict."
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.usage
|
11
|
+
""
|
12
|
+
end
|
13
|
+
|
14
|
+
def setopts!(o)
|
15
|
+
end
|
16
|
+
|
17
|
+
def run
|
18
|
+
needs! :config, :repo
|
19
|
+
|
20
|
+
if @git.resolve!
|
21
|
+
git_to_litdiff!
|
22
|
+
puts "Success!"
|
23
|
+
else
|
24
|
+
puts "Looks like you've got a conflict to resolve!"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|