bookingit 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 175d9e2e4bc7ae8b5e306939a82fa7abaea84501
4
+ data.tar.gz: 7c0b21bcb5891004f1f511acd377897090e24c9b
5
+ SHA512:
6
+ metadata.gz: d1fb9e1d38399731774ec84c4361211fa36ae177d0f02a90662948b2ddf2590a2ff36fcc259b037a03e88dedc37292df03ab3e89417f4fab0f1b490b08eac782
7
+ data.tar.gz: ab1ae505a8b1fe697929e92d7f6968761eae1478546bd7410fda1027a8817b26188d9a31e067c0c9489c55542b9d656074a3b1bd64d8eebed88d1daee9f8de19
data/.gitignore ADDED
@@ -0,0 +1,51 @@
1
+
2
+ # See http://help.github.com/ignore-files/ for more about ignoring files.
3
+ #
4
+ # If you find yourself ignoring temporary files generated by your text editor
5
+ # or operating system, you probably want to add a global ignore instead:
6
+ # git config --global core.excludesfile ~/.gitignore_global
7
+
8
+ # Ignore bundler config
9
+ /.bundle
10
+
11
+ # Ignore the default SQLite database.
12
+ /db/*.sqlite3
13
+
14
+ # Ignore all logfiles and tempfiles.
15
+ /log/*.log
16
+ /tmp
17
+ # vim
18
+ *.sw?
19
+ *.rbc
20
+ *.sassc
21
+ .sass-cache
22
+ capybara-*.html
23
+ .rspec
24
+ /vendor/bundle
25
+ /public/system/*
26
+ /coverage/
27
+ /spec/tmp/*
28
+ **.orig
29
+ rerun.txt
30
+ pickle-email-*.html
31
+
32
+ .rvmrc
33
+ .rbenv-version
34
+
35
+ config/database.yml
36
+
37
+ .idea/*
38
+
39
+ .DS_Store
40
+ # Emacs
41
+ .\#*
42
+ *~
43
+ \#*
44
+
45
+ .vimrc
46
+ .jhw-cache
47
+ .tddium*
48
+ db/tmp
49
+ spec/file-upload/stylecard-from-db.jpg
50
+ .env
51
+ results.html
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ bookingit
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.1.0
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,52 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ bookingit (0.0.1)
5
+ gli
6
+ redcarpet
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ aruba (0.5.4)
12
+ childprocess (>= 0.3.6)
13
+ cucumber (>= 1.1.1)
14
+ rspec-expectations (>= 2.7.0)
15
+ builder (3.2.2)
16
+ childprocess (0.5.1)
17
+ ffi (~> 1.0, >= 1.0.11)
18
+ clean_test (1.0.0)
19
+ faker
20
+ cucumber (1.3.11)
21
+ builder (>= 2.1.2)
22
+ diff-lcs (>= 1.1.3)
23
+ gherkin (~> 2.12)
24
+ multi_json (>= 1.7.5, < 2.0)
25
+ multi_test (>= 0.0.2)
26
+ diff-lcs (1.2.5)
27
+ faker (1.2.0)
28
+ i18n (~> 0.5)
29
+ ffi (1.9.3)
30
+ gherkin (2.12.2)
31
+ multi_json (~> 1.3)
32
+ gli (2.9.0)
33
+ i18n (0.6.9)
34
+ json (1.8.1)
35
+ multi_json (1.8.4)
36
+ multi_test (0.0.3)
37
+ rake (10.1.1)
38
+ rdoc (4.1.1)
39
+ json (~> 1.4)
40
+ redcarpet (3.1.1)
41
+ rspec-expectations (2.14.5)
42
+ diff-lcs (>= 1.1.3, < 2.0)
43
+
44
+ PLATFORMS
45
+ ruby
46
+
47
+ DEPENDENCIES
48
+ aruba
49
+ bookingit!
50
+ clean_test
51
+ rake
52
+ rdoc
data/README.rdoc ADDED
@@ -0,0 +1,103 @@
1
+ = bookingit
2
+
3
+ A basic publishing system that takes Mardown and a Git repository and produces a readable "book" in the following forms:
4
+
5
+ * Website
6
+ * PDF
7
+ * EBook
8
+
9
+ The idea is to easily show the evolution of code over the course of the book, based entirely on git diffs and pull requests.
10
+
11
+ == Example
12
+
13
+
14
+ Here is how our controller looks currently:
15
+
16
+ git:///path/to/repo.git/app/controlleres/users_controller.rb#initial-version
17
+
18
+ We'd like to change the mailer call to use Resque
19
+
20
+ git:///path/to/repo.git/app/controllers/users_controller.rb#initial-version..add-resque-to-controller
21
+
22
+
23
+ This bit of Markdown would be interpretted as if the contents were placed inline like so:
24
+
25
+ Here is how our controller looks currently:
26
+
27
+ ```ruby
28
+ class UsersController < ApplicationController::Base
29
+ def create
30
+ @user = User.new(params.require(:user))
31
+ if @user.save
32
+ UserMailer.welcome_email(user).deliver
33
+ redirect_to root_path
34
+ else
35
+ render 'new'
36
+ end
37
+ end
38
+ end
39
+ ```
40
+
41
+ We'd like to change the mailer call to use Resque
42
+
43
+ ```diff
44
+ --- a/app/controllers/users_controller.rb
45
+ +++ b/app/controllers/users_controller.rb
46
+ def create
47
+ @user = User.new(params.require(:user))
48
+ if @user.save
49
+ - UserMailer.welcome_email(user).deliver
50
+ + Resque.enqueue(WelcomeEmailJob,user.id)
51
+ redirect_to root_path
52
+ else
53
+ ```
54
+
55
+ We can also insert the output of commands:
56
+
57
+ Now, let's run our tests
58
+
59
+ sh:///path/to/wherever#rake test
60
+
61
+ This would be as if the output were inline like so:
62
+
63
+
64
+ Now, let's run our tests.
65
+
66
+ ```bash
67
+ > rake test
68
+ ...........................
69
+
70
+ Finished in 0.00946 seconds
71
+ 27 examples, 0 failures
72
+
73
+ Randomized with seed 43200
74
+ ```
75
+
76
+ == TODO
77
+
78
+ Given the above, a minimal solution would be:
79
+
80
+ * Given some markdown files
81
+ * And a configuration file
82
+ * Be able to generate a multi-page HTML5 website with a table of contents
83
+
84
+ === Configuration
85
+
86
+ At the bare minimum the configuration file needs to indicate a structure that maps sections to markdown files. Something like this:
87
+
88
+ {
89
+ front_matter: [
90
+ "acknowledgements.md",
91
+ "intro.md"
92
+ ],
93
+ main_matter: [
94
+ "getting_started.md",
95
+ ["our_first_controller.md","our_first_model.md","running_tests.md"],
96
+ "chapter3*.md",
97
+ ],
98
+ back_matter: [
99
+ "glossary.md"
100
+ ]
101
+ }
102
+
103
+ We have front, main, and back matter. Inside each we can provide a list of files the be used in order, that represent "chapters" in that section. A chapter can be specified either as a single file, a list of files that are subsections, or a glob. No markup is added, this just specifies the order of processing and how to make the TOC.
data/Rakefile ADDED
@@ -0,0 +1,48 @@
1
+ require 'rake/clean'
2
+ require 'rubygems'
3
+ require 'rubygems/package_task'
4
+ require 'rdoc/task'
5
+ require 'cucumber'
6
+ require 'cucumber/rake/task'
7
+ require 'bundler'
8
+
9
+ Bundler::GemHelper.install_tasks
10
+
11
+ Rake::RDocTask.new do |rd|
12
+ rd.main = "README.rdoc"
13
+ rd.rdoc_files.include("README.rdoc","lib/**/*.rb","bin/**/*")
14
+ rd.title = 'Your application title'
15
+ end
16
+
17
+ spec = eval(File.read('bookingit.gemspec'))
18
+
19
+ Gem::PackageTask.new(spec) do |pkg|
20
+ end
21
+ CUKE_RESULTS = 'results.html'
22
+ CLEAN << CUKE_RESULTS
23
+ desc 'Run features'
24
+ Cucumber::Rake::Task.new(:features) do |t|
25
+ opts = "features --format html -o #{CUKE_RESULTS} --format progress -x"
26
+ opts += " --tags #{ENV['TAGS']}" if ENV['TAGS']
27
+ t.cucumber_opts = opts
28
+ t.fork = false
29
+ end
30
+
31
+ desc 'Run features tagged as work-in-progress (@wip)'
32
+ Cucumber::Rake::Task.new('features:wip') do |t|
33
+ tag_opts = ' --tags ~@pending'
34
+ tag_opts = ' --tags @wip'
35
+ t.cucumber_opts = "features --format html -o #{CUKE_RESULTS} --format pretty -x -s#{tag_opts}"
36
+ t.fork = false
37
+ end
38
+
39
+ task :cucumber => :features
40
+ task 'cucumber:wip' => 'features:wip'
41
+ task :wip => 'features:wip'
42
+ require 'rake/testtask'
43
+ Rake::TestTask.new do |t|
44
+ t.libs << "test"
45
+ t.test_files = FileList['test/*_test.rb']
46
+ end
47
+
48
+ task :default => [:test,:features]
data/bin/bookingit ADDED
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env ruby
2
+ require 'gli'
3
+ require 'bookingit'
4
+
5
+ include GLI::App
6
+ include FileUtils
7
+
8
+ program_desc 'Manage a bookingit book'
9
+
10
+ version Bookingit::VERSION
11
+
12
+ desc 'Set up a new book'
13
+ arg_name 'dir (defaults to .)'
14
+ command :init do |c|
15
+ c.action do |global_options,options,args|
16
+ dir = args.shift || "."
17
+ chdir dir do
18
+ File.open('config.json','w') do |file|
19
+ file.puts %{
20
+ {
21
+ "front_matter": "front.md",
22
+ "main_matter": "main.md",
23
+ "back_matter": "back.md",
24
+ }
25
+ }
26
+ end
27
+ File.open("front.md",'w') do |file|
28
+ file.puts "# Intro Goes Here"
29
+ end
30
+ File.open("main.md",'w') do |file|
31
+ file.puts "# Main stuff here"
32
+ end
33
+ File.open("back.md",'w') do |file|
34
+ file.puts "# Appendeces and whatnot"
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ desc 'build your book from markdown files'
41
+ arg_name 'config_file output_dir'
42
+ command :build do |c|
43
+ c.action do |global_options,options,args|
44
+ puts pwd
45
+ config = Bookingit::Config.new(File.read(args.shift),File.expand_path('.'))
46
+ output_dir = args.shift
47
+ mkdir output_dir unless Dir.exists?(output_dir)
48
+
49
+ renderer = Bookingit::Renderer.new
50
+ redcarpet = Redcarpet::Markdown.new(renderer, no_intra_emphasis: true,
51
+ tables: true,
52
+ fenced_code_blocks: true,
53
+ autolink: true,
54
+ strikethrough: true,
55
+ superscript: true)
56
+
57
+ chdir output_dir do
58
+ File.open('index.html','w') do |index|
59
+ index.puts %{<!DOCTYPE html>
60
+ <html>
61
+ <head>
62
+ </head>
63
+ <body>
64
+ }
65
+ index.puts "<ol>"
66
+ %w(front_matter main_matter back_matter).each do |matter|
67
+ index.puts "<li>#{matter}<ol>"
68
+ config.send(matter).chapters.each_with_index do |chapter,i|
69
+ contents = if chapter.path.nil?
70
+ chapter.sections.map(&:path).map { |path|
71
+ File.read(path)
72
+ }.join("\n")
73
+ else
74
+ File.read(chapter.path)
75
+ end
76
+
77
+ output_file = "#{matter}_#{i+1}.html"
78
+ File.open(output_file,'w') do |file|
79
+ file.puts redcarpet.render(contents)
80
+ end
81
+ title = (Array(renderer.headers[1]) +
82
+ Array(renderer.headers[2]) +
83
+ Array(renderer.headers[3]) +
84
+ Array(renderer.headers[4]) +
85
+ Array(renderer.headers[5]) +
86
+ Array(renderer.headers[6])).first
87
+ index.puts "<li><a href='#{output_file}'>#{title}</a></li>"
88
+ end
89
+ index.puts "</ol></li>"
90
+ end
91
+ index.puts "</ol>"
92
+ index.puts %{
93
+
94
+ </body>
95
+ </html>
96
+ }
97
+ end
98
+ end
99
+ end
100
+ end
101
+
102
+ pre do |global,command,options,args|
103
+ true
104
+ end
105
+
106
+ post do |global,command,options,args|
107
+ end
108
+
109
+ on_error do |exception|
110
+ true
111
+ end
112
+
113
+ exit run(ARGV)
data/bookingit.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # Ensure we require the local version and not one we might have installed already
2
+ require File.join([File.dirname(__FILE__),'lib','bookingit','version.rb'])
3
+ spec = Gem::Specification.new do |s|
4
+ s.name = 'bookingit'
5
+ s.version = Bookingit::VERSION
6
+ s.author = 'Dave Copeland'
7
+ s.email = 'davetron5000@gmail.com'
8
+ s.homepage = 'http://www.naildrivin5.com'
9
+ s.platform = Gem::Platform::RUBY
10
+ s.summary = 'Write a code-heavy book in Markdown'
11
+ # Add your other files here if you make them
12
+ s.require_paths << 'lib'
13
+ s.has_rdoc = true
14
+ s.extra_rdoc_files = ['README.rdoc']
15
+ s.rdoc_options << '--title' << 'bookingit' << '--main' << 'README.rdoc' << '-ri'
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.add_development_dependency('rake')
20
+ s.add_development_dependency('rdoc')
21
+ s.add_development_dependency('aruba')
22
+ s.add_development_dependency('clean_test')
23
+ s.add_runtime_dependency('gli')
24
+ s.add_runtime_dependency('redcarpet')
25
+ end
@@ -0,0 +1,81 @@
1
+ Feature: App does what it's supposed to do
2
+ In order to build a kickass website
3
+ I want to use bookingit to translate markdown
4
+ and all that
5
+
6
+ Scenario: App works
7
+ Given the file "intro.md" contains:
8
+ """
9
+ # My awesome book
10
+
11
+ This is the introduction
12
+ """
13
+ And the file "chapter1.md" contains:
14
+ """
15
+ # It Begins
16
+
17
+ This is the beginning
18
+
19
+ ```
20
+ sh:///# ls
21
+ ```
22
+ """
23
+ And the file "chapter2.1.md" contains:
24
+ """
25
+ # The continuation
26
+
27
+ This is how we work
28
+
29
+ ## Some section
30
+
31
+ Some more stuff
32
+ """
33
+ And the file "chapter2.2.md" contains:
34
+ """
35
+ ## Some other section
36
+
37
+ Even more stuff
38
+ """
39
+ And the file "appendix.md" contains:
40
+ """
41
+ # Glossary
42
+
43
+ This is the glossary
44
+ """
45
+ And this config file:
46
+ """
47
+ {
48
+ "front_matter": [
49
+ "intro.md"
50
+ ],
51
+ "main_matter": [
52
+ "chapter1.md",
53
+ "chapter2.*.md"
54
+ ],
55
+ "back_matter": [
56
+ "appendix.md"
57
+ ]
58
+ }
59
+ """
60
+ When I run `bookingit build config.json book`
61
+ Then the exit status should be 0
62
+ And the file "book/front_matter_1.html" should contain "This is the introduction"
63
+ And the file "book/main_matter_1.html" should contain "This is the beginning"
64
+ And the file "book/main_matter_1.html" should contain "ls"
65
+ And the file "book/main_matter_2.html" should contain "This is how we work"
66
+ And the file "book/main_matter_2.html" should contain "Even more stuff"
67
+ And the file "book/back_matter_1.html" should contain "This is the glossary"
68
+ And the file "book/index.html" should contain "front_matter_1.html"
69
+ And the file "book/index.html" should contain "My awesome book"
70
+ And the file "book/index.html" should contain "main_matter_1.html"
71
+ And the file "book/index.html" should contain "It Begins"
72
+ And the file "book/index.html" should contain "main_matter_2.html"
73
+ And the file "book/index.html" should contain "The continuation"
74
+ And the file "book/index.html" should contain "back_matter_1.html"
75
+ And the file "book/index.html" should contain "Glossary"
76
+
77
+ @wip
78
+ Scenario: Init a new book
79
+ When I run `bookingit init`
80
+ Then a file named "config.json" should exist
81
+
@@ -0,0 +1,26 @@
1
+ require 'tempfile'
2
+ require 'fileutils'
3
+
4
+ When /^I get help for "([^"]*)"$/ do |app_name|
5
+ @app_name = app_name
6
+ step %(I run `#{app_name} help`)
7
+ end
8
+
9
+ Given(/^the file "(.*?)" contains:$/) do |filename, contents|
10
+ FileUtils.chdir "tmp/aruba" do
11
+ @files_created << filename
12
+ File.open(filename,'w') do |file|
13
+ file.puts contents
14
+ end
15
+ end
16
+ end
17
+
18
+ Given(/^this config file:$/) do |string|
19
+ FileUtils.chdir "tmp/aruba" do
20
+ @files_created << "config.json"
21
+ File.open("config.json",'w') do |file|
22
+ file.puts string
23
+ end
24
+ end
25
+ end
26
+
@@ -0,0 +1,19 @@
1
+ require 'aruba/cucumber'
2
+
3
+ ENV['PATH'] = "#{File.expand_path(File.dirname(__FILE__) + '/../../bin')}#{File::PATH_SEPARATOR}#{ENV['PATH']}"
4
+ LIB_DIR = File.join(File.expand_path(File.dirname(__FILE__)),'..','..','lib')
5
+
6
+ Before do
7
+ # Using "announce" causes massive warnings on 1.9.2
8
+ @puts = true
9
+ @original_rubylib = ENV['RUBYLIB']
10
+ @files_created = []
11
+ ENV['RUBYLIB'] = LIB_DIR + File::PATH_SEPARATOR + ENV['RUBYLIB'].to_s
12
+ end
13
+
14
+ After do
15
+ ENV['RUBYLIB'] = @original_rubylib
16
+ @files_created.each do |file|
17
+ FileUtils.rm file
18
+ end
19
+ end
data/lib/bookingit.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'bookingit/version.rb'
2
+ require 'bookingit/renderer.rb'
3
+ require 'bookingit/config.rb'
@@ -0,0 +1,56 @@
1
+ require 'fileutils'
2
+ require 'json'
3
+
4
+ module Bookingit
5
+ class Config
6
+ include FileUtils
7
+
8
+ attr_reader :front_matter,
9
+ :main_matter,
10
+ :back_matter
11
+
12
+ def initialize(config_json,root_dir)
13
+ config_hash = JSON.parse(config_json)
14
+
15
+ @front_matter = Matter.new(config_hash['front_matter'],root_dir)
16
+ @main_matter = Matter.new(config_hash['main_matter'],root_dir)
17
+ @back_matter = Matter.new(config_hash['back_matter'],root_dir)
18
+ end
19
+
20
+ class Matter
21
+ attr_reader :chapters
22
+ def initialize(chapters_config,root_dir)
23
+ @chapters = Array(chapters_config).map { |chapter_config|
24
+ Chapter.new(chapter_config,root_dir)
25
+ }
26
+ end
27
+ end
28
+
29
+ class Chapter
30
+ attr_reader :sections
31
+ attr_reader :path
32
+
33
+ def initialize(chapter_config,root_dir)
34
+ files = Array(chapter_config).flatten(1).map { |file|
35
+ Dir[File.join(root_dir,file)]
36
+ }.flatten
37
+ if files.size == 1
38
+ @sections = []
39
+ @path = files[0]
40
+ else
41
+ @sections = files.map { |file|
42
+ Section.new(file)
43
+ }
44
+ end
45
+ end
46
+ end
47
+
48
+ class Section
49
+ attr_reader :path
50
+ def initialize(path)
51
+ @path = path
52
+ end
53
+ end
54
+ end
55
+
56
+ end
@@ -0,0 +1,68 @@
1
+ require 'redcarpet'
2
+ require 'cgi'
3
+ require 'fileutils'
4
+
5
+ module Bookingit
6
+ class Renderer < Redcarpet::Render::HTML
7
+ include FileUtils
8
+
9
+ attr_accessor :headers
10
+ def header(text,header_level,anchor)
11
+ @headers[header_level] ||= []
12
+ @headers[header_level] << text
13
+ "<h#{header_level}>#{text}</h#{header_level}>"
14
+ end
15
+
16
+ def doc_header
17
+ @headers = {}
18
+ ""
19
+ end
20
+
21
+ EXTENSION_TO_LANGUAGE = {
22
+ '.rb' => 'ruby',
23
+ '.html' => 'html',
24
+ '.scala' => 'scala',
25
+ }
26
+ def block_code(code, language)
27
+ if code.strip =~ /file:\/\/(.*)$/
28
+ path = $1
29
+ code = File.read(path)
30
+ language = EXTENSION_TO_LANGUAGE.fetch(File.extname(path))
31
+ elsif code.strip =~ /git:\/\/(.*)$/
32
+ path = $1
33
+ if path =~ /(^.*).git\/(.*)#([^#]+)$/
34
+ repo_path = $1
35
+ path_in_repo = $2
36
+ reference = $3
37
+ chdir repo_path do
38
+ if reference =~ /^(.+)\.\.(.+)$/
39
+ code = `git diff #{reference}`
40
+ language = 'diff'
41
+ else
42
+ `git checkout #{reference} 2>&1`
43
+ code = File.read(path_in_repo)
44
+ `git checkout master 2>&1`
45
+ language = EXTENSION_TO_LANGUAGE.fetch(File.extname(path_in_repo))
46
+ end
47
+ end
48
+ else
49
+ raise "You must provide a SHA1 or tagname: #{path}"
50
+ end
51
+ elsif code.strip =~ /sh:\/\/(.+)#([^#]+)$/
52
+ path = $1
53
+ command = $2
54
+ chdir path do
55
+ output = `#{command}`
56
+ code = "> #{command}\n#{output}"
57
+ language = 'shell'
58
+ end
59
+ end
60
+ css_class = if language.nil? || language.strip == ''
61
+ ""
62
+ else
63
+ " class=\"language-#{language}\""
64
+ end
65
+ %{<pre><code#{css_class}>#{CGI.escapeHTML(code)}</code></pre>}
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,3 @@
1
+ module Bookingit
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,119 @@
1
+ require 'test_helper'
2
+ require 'tempfile'
3
+ require 'fileutils'
4
+ require 'json'
5
+
6
+ class Bookingit::ConfigTest < Test::Unit::TestCase
7
+
8
+ def setup
9
+ @tempdir = Dir.mktmpdir
10
+ end
11
+
12
+ def teardown
13
+ remove_entry @tempdir
14
+ end
15
+
16
+ test_that "wraps single files in arrays" do
17
+ Given :some_markdown_files
18
+ And {
19
+ @config = {
20
+ front_matter: "foo.md",
21
+ main_matter: "bar.md",
22
+ back_matter: "baz.md",
23
+ }
24
+ }
25
+ When {
26
+ @normalized_config = Bookingit::Config.new(@config.to_json,@tempdir)
27
+ }
28
+ Then {
29
+ assert_equal 1,@normalized_config.front_matter.chapters.size
30
+ assert_equal File.join(@tempdir,'foo.md'),@normalized_config.front_matter.chapters[0].path
31
+ assert_equal 1,@normalized_config.main_matter.chapters.size
32
+ assert_equal File.join(@tempdir,'bar.md'),@normalized_config.main_matter.chapters[0].path
33
+ assert_equal 0,@normalized_config.main_matter.chapters[0].sections.size
34
+ assert_equal 1,@normalized_config.back_matter.chapters.size
35
+ assert_equal File.join(@tempdir,'baz.md'),@normalized_config.back_matter.chapters[0].path
36
+ }
37
+ end
38
+
39
+ test_that "does nothing to arrays" do
40
+ Given :some_markdown_files
41
+ And {
42
+ @config = {
43
+ front_matter: ["foo.md"],
44
+ main_matter: ["bar.md"],
45
+ back_matter: ["baz.md"],
46
+ }
47
+ }
48
+ When {
49
+ @normalized_config = Bookingit::Config.new(@config.to_json,@tempdir)
50
+ }
51
+ Then {
52
+ assert_equal 1,@normalized_config.front_matter.chapters.size
53
+ assert_equal File.join(@tempdir,'foo.md'),@normalized_config.front_matter.chapters[0].path
54
+ assert_equal 1,@normalized_config.main_matter.chapters.size
55
+ assert_equal File.join(@tempdir,'bar.md'),@normalized_config.main_matter.chapters[0].path
56
+ assert_equal 0,@normalized_config.main_matter.chapters[0].sections.size
57
+ assert_equal 1,@normalized_config.back_matter.chapters.size
58
+ assert_equal File.join(@tempdir,'baz.md'),@normalized_config.back_matter.chapters[0].path
59
+ }
60
+ end
61
+
62
+ test_that "parses sections" do
63
+ Given :some_markdown_files
64
+ And {
65
+ @config = {
66
+ front_matter: ["foo.md"],
67
+ main_matter: [
68
+ "bar.md",
69
+ ["blah1.md","blah2.md"],
70
+ ],
71
+ back_matter: ["baz.md"],
72
+ }
73
+ }
74
+ When {
75
+ @normalized_config = Bookingit::Config.new(@config.to_json,@tempdir)
76
+ }
77
+ Then {
78
+ assert_equal 2,@normalized_config.main_matter.chapters.size,"chapters"
79
+ assert_equal 2,@normalized_config.main_matter.chapters[1].sections.size,"sections"
80
+ }
81
+ end
82
+
83
+ test_that "globs" do
84
+ Given :some_markdown_files
85
+ And {
86
+ @config = {
87
+ front_matter: ["foo.md"],
88
+ main_matter: [
89
+ "bar.md",
90
+ "blah*.md",
91
+ ],
92
+ back_matter: ["baz.md"],
93
+ }
94
+ }
95
+ When {
96
+ @normalized_config = Bookingit::Config.new(@config.to_json,@tempdir)
97
+ }
98
+ Then {
99
+ assert_equal 2,@normalized_config.main_matter.chapters.size
100
+ assert_equal 3,@normalized_config.main_matter.chapters[1].sections.size
101
+ assert_equal File.join(@tempdir,'blah1.md'),@normalized_config.main_matter.chapters[1].sections[0].path
102
+ assert_equal File.join(@tempdir,'blah2.md'),@normalized_config.main_matter.chapters[1].sections[1].path
103
+ assert_equal File.join(@tempdir,'blah3.md'),@normalized_config.main_matter.chapters[1].sections[2].path
104
+ }
105
+ end
106
+
107
+ private
108
+
109
+ def some_markdown_files
110
+ chdir @tempdir do
111
+ system "touch foo.md"
112
+ system "touch baz.md"
113
+ system "touch bar.md"
114
+ system "touch blah1.md"
115
+ system "touch blah2.md"
116
+ system "touch blah3.md"
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,269 @@
1
+ require 'test_helper'
2
+ require 'tempfile'
3
+ require 'fileutils'
4
+
5
+ include FileUtils
6
+
7
+ class RendererTest < Test::Unit::TestCase
8
+
9
+ def setup
10
+ @tempdir = Dir.mktmpdir
11
+ end
12
+
13
+ def teardown
14
+ remove_entry @tempdir
15
+ end
16
+
17
+ test_that "block_code can read a file URL and guess ruby" do
18
+ Given a_file_with_extension(".rb")
19
+ When render_file_url_code_block
20
+ Then {
21
+ assert_equal %{<pre><code class="language-ruby">#{@code}</code></pre>},@html
22
+ }
23
+ end
24
+
25
+ test_that "block_code can read a file URL and guess scala" do
26
+ Given a_file_with_extension(".scala")
27
+ When render_file_url_code_block
28
+ Then {
29
+ assert_equal %{<pre><code class="language-scala">#{@code}</code></pre>},@html
30
+ }
31
+ end
32
+
33
+ test_that "it HTML-escapes" do
34
+ Given a_file_with_extension_and_contents('.html',%{<!DOCTYPE html>
35
+ <html>
36
+ <body>
37
+ <h1>HELLO!</h1>
38
+ <h2>&amp; Goodbye</h2>
39
+ </body>
40
+ </html>
41
+ })
42
+ When render_file_url_code_block
43
+ Then {
44
+ assert_equal %{<pre><code class="language-html">&lt;!DOCTYPE html&gt;
45
+ &lt;html&gt;
46
+ &lt;body&gt;
47
+ &lt;h1&gt;HELLO!&lt;/h1&gt;
48
+ &lt;h2&gt;&amp;amp; Goodbye&lt;/h2&gt;
49
+ &lt;/body&gt;
50
+ &lt;/html&gt;
51
+ </code></pre>},@html
52
+ }
53
+ end
54
+
55
+ test_that "a git url without a SHA1 or tag raises" do
56
+ Given a_git_repo_with_file("foo.rb")
57
+ When {
58
+ @code = -> {
59
+ Bookingit::Renderer.new.block_code(@file_git_url,nil)
60
+ }
61
+ }
62
+ Then {
63
+ assert_raises RuntimeError,&@code
64
+ }
65
+ end
66
+
67
+ test_that "a git url with a SHA1 gets that version" do
68
+ Given a_git_repo_with_two_verions_of_file("foo.rb")
69
+ When {
70
+ @parsed_versions = Hash[@versions.map { |sha1,_|
71
+ [sha1, Bookingit::Renderer.new.block_code(@file_git_url + "##{sha1}",nil)]
72
+ }]
73
+ }
74
+ Then {
75
+ @parsed_versions.each do |sha1,code|
76
+ assert_equal %{<pre><code class="language-ruby">#{@versions[sha1]}\n</code></pre>},code,"For SHA: #{sha1}"
77
+ end
78
+ }
79
+ end
80
+
81
+ test_that "a git url with a tag gets that version" do
82
+ Given a_git_repo_with_two_tagged_verions_of_file("foo.rb")
83
+ When {
84
+ @parsed_versions = Hash[@versions.map { |tagname,_|
85
+ [tagname, Bookingit::Renderer.new.block_code(@file_git_url + "##{tagname}",nil)]
86
+ }]
87
+ }
88
+ Then {
89
+ @parsed_versions.each do |tagname,code|
90
+ assert_equal %{<pre><code class="language-ruby">#{@versions[tagname]}\n</code></pre>},code,"For Tag: #{tagname}"
91
+ end
92
+ }
93
+ end
94
+
95
+ test_that "a git url with a diff spec shows the diff instead" do
96
+ Given a_git_repo_with_two_tagged_verions_of_file("foo.rb")
97
+ When {
98
+ url = @file_git_url + "#" + @versions.keys[0] + ".." + @versions.keys[1]
99
+ @html = Bookingit::Renderer.new.block_code(url,nil)
100
+ }
101
+ Then {
102
+ assert_match /<pre><code class=\"language-diff\">diff --git/,@html
103
+ assert_match /a\/foo.rb b\/foo.rb/,@html
104
+ assert_match /index [a-z0-9]+..[a-z0-9]+ 100644/,@html
105
+ assert_match /\-\-\- a\/foo.rb/,@html
106
+ assert_match /\+\+\+ b\/foo.rb/,@html
107
+ }
108
+ end
109
+
110
+ test_that "an sh url will run the given command and put the contents into the output" do
111
+ Given {
112
+ chdir @tempdir do
113
+ mkdir "play"
114
+ chdir "play" do
115
+ system "touch blah"
116
+ system "touch bar"
117
+ system "touch quux"
118
+ end
119
+ end
120
+ }
121
+ When {
122
+ @html = Bookingit::Renderer.new.block_code("sh://#{@tempdir}/play#ls -1",nil)
123
+ }
124
+ Then {
125
+ assert_equal %{<pre><code class="language-shell">&gt; ls -1
126
+ bar
127
+ blah
128
+ quux
129
+ </code></pre>},@html
130
+ }
131
+ end
132
+
133
+ test_that "we pass through inline code blocks" do
134
+ When {
135
+ @html = Bookingit::Renderer.new.block_code("class Foo", 'coffeescript')
136
+ }
137
+ Then {
138
+ assert_equal %{<pre><code class="language-coffeescript">class Foo</code></pre>},@html
139
+ }
140
+ end
141
+
142
+ test_that "we omit the language class if it's not provided in inline code" do
143
+ When {
144
+ @html = Bookingit::Renderer.new.block_code("class Foo", nil)
145
+ }
146
+ Then {
147
+ assert_equal %{<pre><code>class Foo</code></pre>},@html
148
+ }
149
+ end
150
+
151
+ private
152
+
153
+ def create_and_commit_file(file,contents)
154
+ File.open(file,'w') do |file|
155
+ file.puts contents
156
+ end
157
+ system "git add . #{devnull}"
158
+ system "git commit -m \"new file\" #{devnull}"
159
+ `git rev-parse HEAD`.chomp
160
+ end
161
+
162
+ def a_git_repo_with_two_verions_of_file(file)
163
+ -> {
164
+ @versions = {}
165
+ git_repo_in_tempdir do
166
+ code = %{class Foo
167
+ def initialize
168
+ end
169
+ end}
170
+ 2.times {
171
+ @versions[create_and_commit_file(file,code)] = code
172
+
173
+ code = %{class Foo
174
+ def initialize
175
+ @added = true
176
+ end
177
+ end}
178
+ }
179
+ create_and_commit_file(file,code)
180
+ # make sure test doesn't get the HEAD version
181
+ end
182
+ @file_git_url = "git://#{File.join(@tempdir,'git_repo.git')}/#{file}"
183
+ }
184
+ end
185
+
186
+ def a_git_repo_with_two_tagged_verions_of_file(file)
187
+ -> {
188
+ @versions = {}
189
+ git_repo_in_tempdir do
190
+ code = %{class Foo
191
+ def initialize
192
+ end
193
+ end}
194
+ 2.times { |index|
195
+ create_and_commit_file(file,code)
196
+ tag = "tag-#{index}"
197
+ system "git tag #{tag} #{devnull}"
198
+
199
+ @versions[tag] = code
200
+
201
+ code = %{class Foo
202
+ def initialize
203
+ @added = true
204
+ end
205
+ end}
206
+ }
207
+ create_and_commit_file(file,code)
208
+ # make sure test doesn't get the HEAD version
209
+ end
210
+ @file_git_url = "git://#{File.join(@tempdir,'git_repo.git')}/#{file}"
211
+ }
212
+ end
213
+
214
+ def git_repo_in_tempdir(&block)
215
+ chdir @tempdir do
216
+ mkdir 'git_repo'
217
+ chdir 'git_repo' do
218
+ system "git init #{devnull}"
219
+ system "git add . #{devnull}"
220
+ system "git commit -m \"initial commit\" #{devnull}"
221
+ block.()
222
+ end
223
+ end
224
+ end
225
+
226
+ def a_git_repo_with_file(file)
227
+ -> {
228
+ git_repo_in_tempdir do
229
+ @code = %{class Foo
230
+ def initialize
231
+ end
232
+ end}
233
+ create_and_commit_file(file,@code)
234
+ end
235
+ @file_git_url = "git://#{File.join(@tempdir,'git_repo.git')}/#{file}"
236
+ }
237
+ end
238
+
239
+ def render_file_url_code_block
240
+ -> {
241
+ @html = Bookingit::Renderer.new.block_code("file://#{@path}",nil)
242
+ }
243
+ end
244
+
245
+ def a_file_with_extension_and_contents(extension,contents)
246
+ -> {
247
+ file = Tempfile.new(['foo',extension])
248
+ @path = file.path
249
+ @code = contents
250
+ File.open(@path,'w') do |file|
251
+ file.puts @code
252
+ end
253
+ }
254
+ end
255
+
256
+ def a_file_with_extension(extension)
257
+ a_file_with_extension_and_contents(extension,%{class SomeCode
258
+ def initialize(ohyeah)
259
+ @oh yeah = ohyeah
260
+ end
261
+ end
262
+ })
263
+ end
264
+
265
+ def devnull
266
+ return "" if ENV['DEBUG']
267
+ " 2>&1 > /dev/null"
268
+ end
269
+ end
@@ -0,0 +1,14 @@
1
+ require 'test/unit'
2
+ require 'clean_test/test_case'
3
+ require 'bookingit'
4
+
5
+ # Add test libraries you want to use here, e.g. mocha
6
+
7
+ class Test::Unit::TestCase
8
+ include Clean::Test::GivenWhenThen
9
+ include Clean::Test::TestThat
10
+ include Clean::Test::Any
11
+
12
+ # Add global extensions to the test case class here
13
+
14
+ end
metadata ADDED
@@ -0,0 +1,159 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bookingit
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Dave Copeland
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-03-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rdoc
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: aruba
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: clean_test
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: gli
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: redcarpet
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description:
98
+ email: davetron5000@gmail.com
99
+ executables:
100
+ - bookingit
101
+ extensions: []
102
+ extra_rdoc_files:
103
+ - README.rdoc
104
+ files:
105
+ - ".gitignore"
106
+ - ".ruby-gemset"
107
+ - ".ruby-version"
108
+ - Gemfile
109
+ - Gemfile.lock
110
+ - README.rdoc
111
+ - Rakefile
112
+ - bin/bookingit
113
+ - bookingit.gemspec
114
+ - features/bookingit.feature
115
+ - features/step_definitions/bookinggit_steps.rb
116
+ - features/support/env.rb
117
+ - lib/bookingit.rb
118
+ - lib/bookingit/config.rb
119
+ - lib/bookingit/renderer.rb
120
+ - lib/bookingit/version.rb
121
+ - test/config_test.rb
122
+ - test/renderer_test.rb
123
+ - test/test_helper.rb
124
+ homepage: http://www.naildrivin5.com
125
+ licenses: []
126
+ metadata: {}
127
+ post_install_message:
128
+ rdoc_options:
129
+ - "--title"
130
+ - bookingit
131
+ - "--main"
132
+ - README.rdoc
133
+ - "-ri"
134
+ require_paths:
135
+ - lib
136
+ - lib
137
+ required_ruby_version: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - ">="
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ required_rubygems_version: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ requirements: []
148
+ rubyforge_project:
149
+ rubygems_version: 2.2.0.rc.1
150
+ signing_key:
151
+ specification_version: 4
152
+ summary: Write a code-heavy book in Markdown
153
+ test_files:
154
+ - features/bookingit.feature
155
+ - features/step_definitions/bookinggit_steps.rb
156
+ - features/support/env.rb
157
+ - test/config_test.rb
158
+ - test/renderer_test.rb
159
+ - test/test_helper.rb