marksman 0.0.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 +4 -4
- data/.gitignore +23 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +7 -0
- data/Guardfile +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +80 -0
- data/Rakefile +14 -0
- data/bin/marksman +8 -0
- data/lib/marksman.rb +13 -0
- data/lib/marksman/cli.rb +29 -0
- data/lib/marksman/converter.rb +50 -0
- data/lib/marksman/equality.rb +15 -0
- data/lib/marksman/parser.rb +55 -0
- data/lib/marksman/presentation.rb +26 -0
- data/lib/marksman/slide.rb +12 -0
- data/lib/marksman/theme.rb +21 -0
- data/lib/marksman/version.rb +3 -0
- data/lib/marksman/watcher.rb +47 -0
- data/lib/marksman/writer.rb +18 -0
- data/marksman.gemspec +32 -0
- data/spec/data/example.md +11 -0
- data/spec/data/example_without_metadata.md +7 -0
- data/spec/data/output/index.html +44 -0
- data/spec/marksman/cli_spec.rb +26 -0
- data/spec/marksman/converter_spec.rb +40 -0
- data/spec/marksman/parser_spec.rb +64 -0
- data/spec/marksman/presentation_spec.rb +25 -0
- data/spec/marksman/slide_spec.rb +17 -0
- data/spec/marksman/theme_spec.rb +29 -0
- data/spec/marksman/watcher_spec.rb +45 -0
- data/spec/marksman/writer_spec.rb +15 -0
- data/spec/spec_helper.rb +12 -0
- data/themes/blank/css/blank.css +5 -0
- data/themes/blank/css/tomorrow-night.css +93 -0
- data/themes/blank/index.haml +21 -0
- data/themes/blank/js/highlight.min.js +1 -0
- data/themes/plain/css/default.css +42 -0
- data/themes/plain/css/github.css +125 -0
- data/themes/plain/css/tomorrow-night.css +93 -0
- data/themes/plain/css/tomorrow.css +90 -0
- data/themes/plain/index.haml +18 -0
- data/themes/plain/js/highlight.min.js +1 -0
- metadata +210 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 057ad0bdc1acdca0c3c4683862837088232521df
|
4
|
+
data.tar.gz: a105f581953f1c52d9416dda50c63fca60c0b82c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7c355dbbc9670e5fa05583a04f4b3caecae926d318a8a6a2379f4d4d09a296a95ac2afa08e9b5ec90fb53f29263236607c0ac33d23087865246471772cafa11d
|
7
|
+
data.tar.gz: 90d00af80c4ba2a6873250d568150c53088678a3132898be165d3ca18e88e8e7d342fc83854d5fe36b5b36a9f3723d1537db45fb789e5dd9d0da3f3c77bbdea4
|
data/.gitignore
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
public
|
19
|
+
*.bundle
|
20
|
+
*.so
|
21
|
+
*.o
|
22
|
+
*.a
|
23
|
+
mkmf.log
|
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Bodo Tasche
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
# Marksman
|
2
|
+
|
3
|
+
[](https://codeclimate.com/github/bitboxer/marksman)
|
4
|
+
[](https://coveralls.io/r/bitboxer/marksman?branch=master)
|
5
|
+
[](http://rubygems.org/gems/marksman)
|
6
|
+
|
7
|
+
This is an opinionated approach to presentations. I don't want to
|
8
|
+
think a lot about the design or how to place my text on a slide.
|
9
|
+
|
10
|
+
I want to focus on the text. On what I want to say. On the important
|
11
|
+
part of the presentation.
|
12
|
+
|
13
|
+
If you think the same and love markdown, this might be for you.
|
14
|
+
|
15
|
+
## Installation
|
16
|
+
|
17
|
+
gem install marksman
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
This generates a public folder with all things needed from the
|
22
|
+
markdown file `presentation.md`:
|
23
|
+
|
24
|
+
marksman generate presentation.md
|
25
|
+
|
26
|
+
You can also run it as a watcher that regenerates the presentation each
|
27
|
+
time the markdown file was changed
|
28
|
+
|
29
|
+
marksman watch presentation.md
|
30
|
+
|
31
|
+
## File format
|
32
|
+
|
33
|
+
The system uses plain markdown files with two additions:
|
34
|
+
|
35
|
+
* The header can have a jekyll like yaml block
|
36
|
+
* Slides are separated with `----------`
|
37
|
+
* Presenter Notes within a slide are separated with `**********` from the
|
38
|
+
text in the slide
|
39
|
+
|
40
|
+
Here is an example for that format:
|
41
|
+
|
42
|
+
---
|
43
|
+
title: "How to run a company"
|
44
|
+
theme: "plain"
|
45
|
+
---
|
46
|
+
Bodo Tasche
|
47
|
+
@bitboxer
|
48
|
+
********
|
49
|
+
Here I write what I want to say about me. Aka presenter notes.
|
50
|
+
--------
|
51
|
+
This is code:
|
52
|
+
```
|
53
|
+
def hello(name)
|
54
|
+
puts "Hello #{name}"
|
55
|
+
end
|
56
|
+
```
|
57
|
+
|
58
|
+
## Themes
|
59
|
+
|
60
|
+
Marksman supports themes. You can either set the used theme in the header of the
|
61
|
+
presentation or override that choice by adding `-t name` as a parameter.
|
62
|
+
|
63
|
+
Currently there are only two themes available:
|
64
|
+
|
65
|
+
* `blank` - this renders the presentation as a simple HTML that can be used
|
66
|
+
to print the presentation
|
67
|
+
* `plain` - this is a basic presentation theme
|
68
|
+
|
69
|
+
If you want to create a theme, just copy one of the themes to your project folder and
|
70
|
+
reference the directory name in the header.
|
71
|
+
|
72
|
+
If you have a theme you would love to share, please send a pull request.
|
73
|
+
|
74
|
+
## Contributing
|
75
|
+
|
76
|
+
1. Fork it ( https://github.com/[my-github-username]/marksman/fork )
|
77
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
78
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
79
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
80
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/bin/marksman
ADDED
data/lib/marksman.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'marksman/equality'
|
2
|
+
require 'marksman/cli'
|
3
|
+
require 'marksman/converter'
|
4
|
+
require 'marksman/writer'
|
5
|
+
require 'marksman/parser'
|
6
|
+
require 'marksman/presentation'
|
7
|
+
require 'marksman/slide'
|
8
|
+
require 'marksman/theme'
|
9
|
+
require 'marksman/version'
|
10
|
+
require 'marksman/watcher'
|
11
|
+
|
12
|
+
module Marksman
|
13
|
+
end
|
data/lib/marksman/cli.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'marksman'
|
3
|
+
|
4
|
+
module Marksman
|
5
|
+
class CLI < Thor
|
6
|
+
|
7
|
+
desc 'generate FILE [OUTPUT DIRECTORY]', 'generates a presentation from a markdown file'
|
8
|
+
long_desc <<-LONGDESC
|
9
|
+
`marsksman generate file.md` will parse the markdown file and
|
10
|
+
create a presentation in the folder 'public'
|
11
|
+
|
12
|
+
You can optionally specify the folder where the presentation is stored
|
13
|
+
as a second parameter.
|
14
|
+
|
15
|
+
> $ marksman FILE.md output
|
16
|
+
LONGDESC
|
17
|
+
method_option :theme, desc: 'override the theme in the presentation', aliases: ['-t']
|
18
|
+
def generate(file, target = 'public')
|
19
|
+
Marksman::Writer.new(file, target, options[:theme]).generate
|
20
|
+
end
|
21
|
+
|
22
|
+
desc 'watch FILE [OUTPUT DIRECTORY]', 'same as generate, but watches the file and regenerates it on each change'
|
23
|
+
method_option :theme, desc: 'override the theme in the presentation', aliases: ['-t']
|
24
|
+
def watch(file, target = 'public')
|
25
|
+
Marksman::Watcher.new(file, target, options[:theme]).watch
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'haml'
|
3
|
+
|
4
|
+
module Marksman
|
5
|
+
class Converter
|
6
|
+
|
7
|
+
attr_accessor :presentation, :theme
|
8
|
+
|
9
|
+
def initialize(presentation)
|
10
|
+
@presentation = presentation
|
11
|
+
end
|
12
|
+
|
13
|
+
def write(directory)
|
14
|
+
puts 'Generating HTML...'
|
15
|
+
FileUtils.mkdir_p(directory)
|
16
|
+
Dir.glob(@presentation.theme.path.join('**/*')).each do |file|
|
17
|
+
if File.file? file
|
18
|
+
copy_file(Pathname.new(file), directory)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def copy_file(source, target_dir)
|
26
|
+
target = target_name(source, target_dir)
|
27
|
+
FileUtils.mkdir(target.dirname) unless File.exist? target.dirname
|
28
|
+
if (source.extname == '.haml')
|
29
|
+
convert_haml(source, target.to_s.gsub(/\.haml$/, '.html'))
|
30
|
+
else
|
31
|
+
FileUtils.copy(source, target)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def target_name(file, target_dir)
|
36
|
+
base_file = file.to_s[(@presentation.theme.path.to_s.length + 1)..-1]
|
37
|
+
target_file = Pathname.new(target_dir).join(base_file)
|
38
|
+
end
|
39
|
+
|
40
|
+
def convert_haml(file, output)
|
41
|
+
template = File.read(file)
|
42
|
+
haml_engine = Haml::Engine.new(template)
|
43
|
+
html = haml_engine.render(Object.new, {
|
44
|
+
presentation: @presentation
|
45
|
+
})
|
46
|
+
File.write(output, html)
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Marksman
|
2
|
+
module Equality
|
3
|
+
|
4
|
+
def == (other)
|
5
|
+
self.class == other.class && self.attributes == other.attributes
|
6
|
+
end
|
7
|
+
|
8
|
+
def attributes
|
9
|
+
Hash[instance_variables.map do |attribute|
|
10
|
+
[attribute, instance_variable_get(attribute)]
|
11
|
+
end]
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'redcarpet'
|
2
|
+
require 'ostruct'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module Marksman
|
6
|
+
class Parser
|
7
|
+
|
8
|
+
def parse(file)
|
9
|
+
metadata, markdown = load_file(file)
|
10
|
+
slides = split_slides(markdown).map do |slide|
|
11
|
+
sections = separate_presenter_notes(slide)
|
12
|
+
Slide.new(
|
13
|
+
slide: generate_html(sections.slide).strip,
|
14
|
+
notes: generate_html(sections.notes).strip
|
15
|
+
)
|
16
|
+
end
|
17
|
+
|
18
|
+
Presentation.new(filename: File.basename(file), metadata: metadata, slides: slides)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def load_file(file)
|
24
|
+
content = File.read(file)
|
25
|
+
if content.match /^(---\s*\n.*?\n?)^(?:---\s*$\n?)(.*)/m
|
26
|
+
[parse_yaml($1), $2]
|
27
|
+
else
|
28
|
+
[{}, content]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def parse_yaml(data)
|
33
|
+
yaml = YAML.load(data)
|
34
|
+
yaml.keys.each do |key|
|
35
|
+
yaml[key.to_sym] = yaml.delete key
|
36
|
+
end
|
37
|
+
yaml
|
38
|
+
end
|
39
|
+
|
40
|
+
def separate_presenter_notes(slide)
|
41
|
+
sections = slide.split(/^(?:\*{1}\s?){3,}\s*$/).each(&:strip)
|
42
|
+
Slide.new(slide: sections[0], notes: sections[1])
|
43
|
+
end
|
44
|
+
|
45
|
+
def split_slides(markdown)
|
46
|
+
slides = markdown.split(/^(?:[-]{1}\s?){3,}\s*$/).each(&:strip)
|
47
|
+
end
|
48
|
+
|
49
|
+
def generate_html(slide)
|
50
|
+
markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML,{fenced_code_blocks: true})
|
51
|
+
markdown.render(slide || '')
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Marksman
|
2
|
+
class Presentation
|
3
|
+
include Equality
|
4
|
+
attr_accessor :filename, :metadata, :slides, :theme
|
5
|
+
|
6
|
+
def initialize(options)
|
7
|
+
@filename = options[:filename]
|
8
|
+
@slides = options[:slides] || []
|
9
|
+
@metadata = defaults(filename).merge(options[:metadata] || {})
|
10
|
+
@theme = Theme.new @metadata[:theme]
|
11
|
+
end
|
12
|
+
|
13
|
+
def title
|
14
|
+
@metadata[:title]
|
15
|
+
end
|
16
|
+
|
17
|
+
def defaults(filename)
|
18
|
+
{
|
19
|
+
filename: filename,
|
20
|
+
title: filename,
|
21
|
+
theme: 'plain'
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Marksman
|
2
|
+
class Theme
|
3
|
+
include Equality
|
4
|
+
|
5
|
+
def initialize(name)
|
6
|
+
@name = name
|
7
|
+
end
|
8
|
+
|
9
|
+
def path
|
10
|
+
@path ||= if File.directory?(@name)
|
11
|
+
Pathname.new @name
|
12
|
+
else
|
13
|
+
Pathname.new(File.dirname(__FILE__))
|
14
|
+
.join('../../')
|
15
|
+
.join('themes')
|
16
|
+
.join(@name)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'listen'
|
2
|
+
|
3
|
+
module Marksman
|
4
|
+
class Watcher
|
5
|
+
|
6
|
+
def initialize(file, output_directory, theme_name = nil)
|
7
|
+
@file = Pathname.new file
|
8
|
+
@output_directory = output_directory
|
9
|
+
@theme_name = theme_name
|
10
|
+
end
|
11
|
+
|
12
|
+
def watch
|
13
|
+
update(true)
|
14
|
+
listen
|
15
|
+
end
|
16
|
+
|
17
|
+
def update(start_listener = false)
|
18
|
+
puts 'Updating files...'
|
19
|
+
presentation = Marksman::Writer.new(@file, @output_directory, @theme_name).generate
|
20
|
+
start_theme_listener(presentation.theme) unless @theme_listener
|
21
|
+
end
|
22
|
+
|
23
|
+
def listen
|
24
|
+
puts 'Listening to changes...'
|
25
|
+
@markdown_listener = Listen.to(Pathname.new(@file).dirname) do |modified, added, removed|
|
26
|
+
if modified.include? @file.realpath.to_s
|
27
|
+
update
|
28
|
+
end
|
29
|
+
end
|
30
|
+
@markdown_listener.start
|
31
|
+
sleep
|
32
|
+
end
|
33
|
+
|
34
|
+
def start_theme_listener(theme)
|
35
|
+
@theme_listener = Listen.to(theme.path) do |modified, added, removed|
|
36
|
+
update
|
37
|
+
end
|
38
|
+
@theme_listener.start
|
39
|
+
end
|
40
|
+
|
41
|
+
def stop
|
42
|
+
@markdown_listener.stop
|
43
|
+
@theme_listener.stop if @theme_listener
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|