leg 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '../lib')
4
+
5
+ require 'snaptoken'
6
+
7
+ cli = Snaptoken::CLI.new
8
+ cli.run(ARGV)
9
+
@@ -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