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.
@@ -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
@@ -0,0 +1,17 @@
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
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in ghost_story.gemspec
4
+ gemspec
@@ -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.
@@ -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
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,3 @@
1
+ module GhostStory
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,4 @@
1
+
2
+ class A ; end
3
+
4
+ class A ; end
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: