bookingit 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.
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