ghost_story 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 +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +79 -0
- data/Rakefile +1 -0
- data/bin/ghost_story +12 -0
- data/ghost_story.gemspec +32 -0
- data/lib/commands/thor.rb +35 -0
- data/lib/ghost_story.rb +24 -0
- data/lib/ghost_story/story.rb +20 -0
- data/lib/ghost_story/story_builder.rb +123 -0
- data/lib/ghost_story/version.rb +3 -0
- data/lib/untitled +4 -0
- metadata +147 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 020b2e0af5ba93bd0e06bd61a169e70b81f733a7
|
4
|
+
data.tar.gz: eab86597a9bf8e43da885b7ae63417c43fca8a33
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cb90b38182d47f2292fee3ff53b5c31f8f765c554c87de1bfc71e995fc0e1629b5311c98e33c0c2caf37492d1b4f222d48298de29d77001a98a61167a6b10fd1
|
7
|
+
data.tar.gz: 9c38d6f324b3318bd98c1a9bdbdcc1e05d6f805ea03fec2bd1d6d97620e82afd087441df01cbb88bd82067a4d4b34b1281b4d0331833d054e161a0136d3aada6
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Franklin Webber
|
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,79 @@
|
|
1
|
+
# GhostStory
|
2
|
+
|
3
|
+
Ghost Story allows you to write a story in markdown. The story can then be
|
4
|
+
read back to you. A ghost story is both text and automated scripts that will
|
5
|
+
type out code.
|
6
|
+
|
7
|
+
The initial use case is for composing repeatable screencasts. When you set out
|
8
|
+
to write a screencast you often times compose a script and the code that
|
9
|
+
accompanies it. There are some inherent problems with this manual method of
|
10
|
+
telling a story:
|
11
|
+
|
12
|
+
- Typing the code is cumbersome and error prone
|
13
|
+
- Removing errors and mistyping during the editing process is a waste of time
|
14
|
+
- Editing or updating your screencast later requires you re-create an entire section manually.
|
15
|
+
|
16
|
+
## Installation
|
17
|
+
|
18
|
+
Add this line to your application's Gemfile:
|
19
|
+
|
20
|
+
gem 'ghost_story'
|
21
|
+
|
22
|
+
And then execute:
|
23
|
+
|
24
|
+
$ bundle
|
25
|
+
|
26
|
+
Or install it yourself as:
|
27
|
+
|
28
|
+
$ gem install ghost_story
|
29
|
+
|
30
|
+
## Usage
|
31
|
+
|
32
|
+
First write the script that you want to execute in markdown.
|
33
|
+
|
34
|
+
# Ruby Classes
|
35
|
+
|
36
|
+
If you are already familar with classes in other languages, you will have
|
37
|
+
no time understanding how they are created in Ruby.
|
38
|
+
|
39
|
+
~~~~
|
40
|
+
class Square
|
41
|
+
|
42
|
+
def initialize(height)
|
43
|
+
@height = height
|
44
|
+
end
|
45
|
+
|
46
|
+
attr_reader :height
|
47
|
+
|
48
|
+
def area
|
49
|
+
height * height
|
50
|
+
end
|
51
|
+
end
|
52
|
+
~~~~
|
53
|
+
|
54
|
+
Then with the completed script you run the `ghost_story` binary which will
|
55
|
+
read the story and then create an interactive version which will show you the
|
56
|
+
written parts and then type the code between the code fences.
|
57
|
+
|
58
|
+
> Some limitation in Kramdown, which is used to generate an object representation
|
59
|
+
> of the document, works consistently with the `~~~` instead of the three backticks.
|
60
|
+
|
61
|
+
```
|
62
|
+
$ ghost_story tell ruby_classes.md APPLICATION
|
63
|
+
```
|
64
|
+
|
65
|
+
The application you specify is important. That is the name of the
|
66
|
+
Appliation that the key events will be sent. At the moment, this is
|
67
|
+
fairly simplistic and will really only work with non-Terminal editors.
|
68
|
+
|
69
|
+
> Also, note that if your editor helps you with auto indention when you are
|
70
|
+
> writing code, this will need to be turned off. I found that
|
71
|
+
> with Sublime Text I needed to set `"auto_indent": false` for example.
|
72
|
+
|
73
|
+
## Contributing
|
74
|
+
|
75
|
+
1. Fork it ( http://github.com/<my-github-username>/ghost_story/fork )
|
76
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
77
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
78
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
79
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/ghost_story
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
path = __FILE__
|
4
|
+
while File.symlink?(path)
|
5
|
+
path = File.expand_path(File.readlink(__FILE__), File.dirname(__FILE__))
|
6
|
+
end
|
7
|
+
$:.unshift(File.join(File.dirname(File.expand_path(path)), '..', 'lib'))
|
8
|
+
|
9
|
+
require "ghost_story"
|
10
|
+
require "commands/thor"
|
11
|
+
|
12
|
+
GhostStory::Thor.start
|
data/ghost_story.gemspec
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'ghost_story/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "ghost_story"
|
8
|
+
spec.version = GhostStory::VERSION
|
9
|
+
spec.authors = ["Franklin Webber"]
|
10
|
+
spec.email = ["franklin.webber@gmail.com"]
|
11
|
+
spec.summary = %q{Markdown driving automation used for screencasts or walkthroughs of code where you don't want to type.}
|
12
|
+
|
13
|
+
spec.description = %q{Ghost Story allows you to write a story in markdown. The story can then be
|
14
|
+
read back to you. A ghost story is both text and automated scripts that will
|
15
|
+
type out code.}
|
16
|
+
|
17
|
+
spec.homepage = "https://github.com/burtlo/ghost_story"
|
18
|
+
spec.license = "MIT"
|
19
|
+
|
20
|
+
spec.files = `git ls-files -z`.split("\x0")
|
21
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
22
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
23
|
+
spec.require_paths = ["lib"]
|
24
|
+
|
25
|
+
spec.add_dependency "dutchman", ">= 0.0.1"
|
26
|
+
spec.add_dependency "formatador", "~> 0.2"
|
27
|
+
spec.add_dependency "kramdown", "~> 1.1"
|
28
|
+
spec.add_dependency "thor", "~> 0.18"
|
29
|
+
|
30
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
31
|
+
spec.add_development_dependency "rake"
|
32
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'thor'
|
2
|
+
# require 'thor/group'
|
3
|
+
|
4
|
+
module GhostStory
|
5
|
+
|
6
|
+
class Thor < Thor
|
7
|
+
|
8
|
+
no_tasks do
|
9
|
+
|
10
|
+
def banner
|
11
|
+
"""
|
12
|
+
********************************************************************************
|
13
|
+
Ghost Story BOOO!
|
14
|
+
-------------------------------------------------------------------------------"""
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "tell STORYFILE APPLICATION",
|
20
|
+
"Tell the story contained in the file"
|
21
|
+
def tell(story_file,application=nil)
|
22
|
+
# TODO: find out of the file is real!
|
23
|
+
# TODO: Seems Thor has an options hash, so this is probabyly a bad name
|
24
|
+
options = { application: application }
|
25
|
+
GhostStory.read_file(story_file,options)
|
26
|
+
end
|
27
|
+
|
28
|
+
desc "help", "This commoand"
|
29
|
+
def help
|
30
|
+
say banner
|
31
|
+
print_table self.class.printable_tasks, indent: 4
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
data/lib/ghost_story.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require "kramdown"
|
2
|
+
require "formatador"
|
3
|
+
require "pry"
|
4
|
+
|
5
|
+
require "dutchman"
|
6
|
+
|
7
|
+
require "ghost_story/version"
|
8
|
+
require "ghost_story/story_builder"
|
9
|
+
require "ghost_story/story"
|
10
|
+
|
11
|
+
|
12
|
+
module GhostStory
|
13
|
+
|
14
|
+
def self.read_file(story_file,options = {})
|
15
|
+
read File.read(story_file), options
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.read(story,options = {})
|
19
|
+
story_builder = StoryBuilder.new(options)
|
20
|
+
story = story_builder.build(story)
|
21
|
+
story.read!
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module GhostStory
|
2
|
+
|
3
|
+
class Story
|
4
|
+
def initialize(whole_story)
|
5
|
+
@whole_story = whole_story
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_reader :whole_story
|
9
|
+
|
10
|
+
def read!
|
11
|
+
clear_screen
|
12
|
+
whole_story.each { |piece| piece.call }
|
13
|
+
end
|
14
|
+
|
15
|
+
def clear_screen
|
16
|
+
puts "\e[H\e[2J"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
module GhostStory
|
2
|
+
|
3
|
+
class StoryBuilder
|
4
|
+
|
5
|
+
def initialize(options)
|
6
|
+
@options = options || {}
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_reader :options
|
10
|
+
|
11
|
+
#
|
12
|
+
# @returns [Story] a story object is something that can be executed to tell
|
13
|
+
# the story created by the builder.
|
14
|
+
#
|
15
|
+
def build(story)
|
16
|
+
kram = Kramdown::Document.new(story)
|
17
|
+
|
18
|
+
whole_story = build_story(kram.root)
|
19
|
+
|
20
|
+
Story.new(whole_story)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
#
|
26
|
+
# @returns [Array<lambda>] an array of executable objects which
|
27
|
+
# will either display text to the screen or drive the editor to
|
28
|
+
# type in the desired code.
|
29
|
+
#
|
30
|
+
def build_story(node_with_children)
|
31
|
+
node_with_children.children.map { |node| build_chapter(node) }
|
32
|
+
end
|
33
|
+
|
34
|
+
#
|
35
|
+
# Building a chapter creates and returns a delayed block of code for the
|
36
|
+
# particular node. It is packaged like this so that each chapter can be
|
37
|
+
# placed into an array of all the chapters that need to be executed. Ensuring
|
38
|
+
# that they execute in the correct order.
|
39
|
+
#
|
40
|
+
# @returns [lambda] the code that needs to be written or the text that needs
|
41
|
+
# to be displayed to the reader.
|
42
|
+
def build_chapter(node)
|
43
|
+
if node_contains_code?(node)
|
44
|
+
build_code_chapter(node)
|
45
|
+
else
|
46
|
+
lambda { Formatador.display build_standard_chapter(node) }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# Currently a node that identifies as a codeblock is any node using the
|
52
|
+
# three "~~~" syntax. Previously, I was using the more conventional three
|
53
|
+
# backticks "```" but those are converted to codespans. This is a limitation
|
54
|
+
# of using Kramdown.
|
55
|
+
#
|
56
|
+
def node_contains_code?(node)
|
57
|
+
node.type == :codeblock
|
58
|
+
end
|
59
|
+
|
60
|
+
#
|
61
|
+
# Nodes identified as a code chapter will first ask for input from the person
|
62
|
+
# running the story and then it will execute the story.
|
63
|
+
#
|
64
|
+
def build_code_chapter(node)
|
65
|
+
code = node.value
|
66
|
+
lambda { ask_to_continue ; Dutchman.write(to: application, text: code, speed: :fast, humanize: true) }
|
67
|
+
end
|
68
|
+
|
69
|
+
#
|
70
|
+
# The application to which to write the code.
|
71
|
+
#
|
72
|
+
def application
|
73
|
+
options[:application] || default_application
|
74
|
+
end
|
75
|
+
|
76
|
+
#
|
77
|
+
# This default value is not kosher!
|
78
|
+
#
|
79
|
+
def default_application
|
80
|
+
"Sublime Text"
|
81
|
+
end
|
82
|
+
|
83
|
+
#
|
84
|
+
# Prompts the person running the story to press a key to continue with
|
85
|
+
# with the story. This allows them to read the human parts and continue
|
86
|
+
# with the typed parts as necessary.
|
87
|
+
#
|
88
|
+
def ask_to_continue
|
89
|
+
Formatador.display_line "\n\n*** [bold]Press ENTER to type CODE[/] ***"
|
90
|
+
STDIN.gets
|
91
|
+
end
|
92
|
+
|
93
|
+
#
|
94
|
+
# A non-code portion of the story simply needs to be collected up and
|
95
|
+
# a string needs to be created from it. This method is called recursively
|
96
|
+
# to child elements to create the entire string to be displayed. There
|
97
|
+
# are some simple rules for headers to make them a particular color.
|
98
|
+
#
|
99
|
+
def build_standard_chapter(node)
|
100
|
+
|
101
|
+
story_so_far = ""
|
102
|
+
|
103
|
+
story_so_far += "\n#{header_display_color}" if node.type == :header
|
104
|
+
story_so_far += node.value if node.type == :text
|
105
|
+
|
106
|
+
if not node.children.empty?
|
107
|
+
node.children.each do |child|
|
108
|
+
story_so_far += build_standard_chapter(child).to_s
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
story_so_far += "[/]\n" if node.type == :header
|
113
|
+
|
114
|
+
story_so_far
|
115
|
+
end
|
116
|
+
|
117
|
+
def header_display_color
|
118
|
+
"[green]"
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
data/lib/untitled
ADDED
metadata
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ghost_story
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Franklin Webber
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-03-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: dutchman
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.0.1
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.0.1
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: formatador
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.2'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.2'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: kramdown
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.1'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.1'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: thor
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.18'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.18'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: bundler
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ~>
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.5'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ~>
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.5'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
description: |-
|
98
|
+
Ghost Story allows you to write a story in markdown. The story can then be
|
99
|
+
read back to you. A ghost story is both text and automated scripts that will
|
100
|
+
type out code.
|
101
|
+
email:
|
102
|
+
- franklin.webber@gmail.com
|
103
|
+
executables:
|
104
|
+
- ghost_story
|
105
|
+
extensions: []
|
106
|
+
extra_rdoc_files: []
|
107
|
+
files:
|
108
|
+
- .gitignore
|
109
|
+
- Gemfile
|
110
|
+
- LICENSE.txt
|
111
|
+
- README.md
|
112
|
+
- Rakefile
|
113
|
+
- bin/ghost_story
|
114
|
+
- ghost_story.gemspec
|
115
|
+
- lib/commands/thor.rb
|
116
|
+
- lib/ghost_story.rb
|
117
|
+
- lib/ghost_story/story.rb
|
118
|
+
- lib/ghost_story/story_builder.rb
|
119
|
+
- lib/ghost_story/version.rb
|
120
|
+
- lib/untitled
|
121
|
+
homepage: https://github.com/burtlo/ghost_story
|
122
|
+
licenses:
|
123
|
+
- MIT
|
124
|
+
metadata: {}
|
125
|
+
post_install_message:
|
126
|
+
rdoc_options: []
|
127
|
+
require_paths:
|
128
|
+
- lib
|
129
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
130
|
+
requirements:
|
131
|
+
- - '>='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - '>='
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
requirements: []
|
140
|
+
rubyforge_project:
|
141
|
+
rubygems_version: 2.1.9
|
142
|
+
signing_key:
|
143
|
+
specification_version: 4
|
144
|
+
summary: Markdown driving automation used for screencasts or walkthroughs of code
|
145
|
+
where you don't want to type.
|
146
|
+
test_files: []
|
147
|
+
has_rdoc:
|