eleanor 1.0.0

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,88 @@
1
+ require 'rake'
2
+ require 'rake/clean'
3
+ require 'rake/gempackagetask'
4
+ require 'rake/rdoctask'
5
+
6
+ NAME = 'Eleanor'
7
+ UNIX_NAME = NAME.downcase
8
+ VER = '1.0.0'
9
+
10
+ NONLIB_RDOC_FILES = %w[CHANGELOG INSTALL LICENSE README src/ragel/parser.rl]
11
+
12
+ RDOC_FILES = NONLIB_RDOC_FILES +
13
+ %w[lib/eleanor.rb
14
+ lib/eleanor/hpdfpaper.rb
15
+ lib/eleanor/length.rb]
16
+
17
+ RDOC_OPTS = ['--inline-source',
18
+ '--extension', 'rl=rb',
19
+ '--exclude', 'lib/eleanor/parser.rb',
20
+ '--title', "#{NAME} #{VER} Reference",
21
+ '--main', 'README']
22
+
23
+
24
+ PKG_FILES = FileList['CHANGELOG', 'INSTALL', 'LICENSE', 'README',
25
+ 'Rakefile', 'setup.rb',
26
+ 'bin/*', 'data/**/*', 'examples/*.txt',
27
+ 'lib/*', 'lib/**/*', 'src/**/*']
28
+
29
+ CLEAN.include %w[.config InstalledFiles doc examples/*.pdf pkg]
30
+
31
+ GEMSPEC=
32
+ Gem::Specification.new do |s|
33
+ s.name= UNIX_NAME
34
+ s.version= VER
35
+ s.has_rdoc= true
36
+ s.rdoc_options += RDOC_OPTS
37
+ s.extra_rdoc_files= NONLIB_RDOC_FILES
38
+ s.summary= 'Formats speculative screenplays'
39
+ s.description= <<-EOF
40
+ Eleanor is a Ruby script and accompanying library for formatting
41
+ speculative screenplays. It parses plain text written in a simple format
42
+ and outputs pretty PDF that conforms to standard rules of screenplay
43
+ layout. Eleanor's primary goal is to create PDF that is indistinguishable
44
+ from PDF produced by professional screenwriting software such as Final
45
+ Draft.
46
+ EOF
47
+ s.author= 'chiisaitsu'
48
+ s.email= 'chiisaitsu@gmail.com'
49
+ s.homepage= 'http://rubyforge.org/projects/eleanor'
50
+ s.files= PKG_FILES
51
+ s.executables= ['eleanor']
52
+ s.requirements << 'libHaru Free PDF Library: http://libharu.org'
53
+ s.rubyforge_project= 'eleanor'
54
+ end
55
+
56
+ desc 'rake build'
57
+ task :default => [:build]
58
+
59
+ desc 'Build the parser with Ragel'
60
+ task :build do
61
+ sh "ragel -R -o lib/eleanor/parser.rb src/ragel/parser.rl"
62
+ end
63
+
64
+ desc 'Build the examples'
65
+ task :examples do
66
+ Dir.glob('examples/*.txt') do |fname|
67
+ sh "ruby -I./lib bin/eleanor -c data/eleanor/eleanor.yaml #{fname}"
68
+ end
69
+ end
70
+
71
+ desc 'Install to site_ruby'
72
+ task :install do
73
+ sh "ruby setup.rb"
74
+ end
75
+
76
+ task :package => [:clean]
77
+
78
+ Rake::GemPackageTask.new(GEMSPEC) do |t|
79
+ t.need_tar_gz= true
80
+ t.need_zip= true
81
+ t.gem_spec= GEMSPEC
82
+ end
83
+
84
+ Rake::RDocTask.new do |t|
85
+ t.options= RDOC_OPTS
86
+ t.rdoc_dir= 'doc/rdoc'
87
+ t.rdoc_files= RDOC_FILES
88
+ end
@@ -0,0 +1,127 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Copyright (c) 2008 chiisaitsu <chiisaitsu@gmail.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+ begin
24
+ require 'eleanor'
25
+ rescue LoadError
26
+ $LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
27
+ require 'eleanor'
28
+ end
29
+
30
+ require 'optparse'
31
+
32
+ usr_config_fn= File.join(ENV['HOME'] || '', '.eleanorrc')
33
+ sys_config_fn= File.join(Config::CONFIG['datadir'], 'eleanor', 'eleanor.yaml')
34
+ rel_config_fn= File.expand_path(File.join(File.dirname(__FILE__), '..',
35
+ 'data', 'eleanor', 'eleanor.yaml'))
36
+
37
+ conf= {
38
+ :paper => 'eleanor/hpdfpaper',
39
+ :config => if File.exist? usr_config_fn
40
+ usr_config_fn
41
+ elsif File.exist? sys_config_fn
42
+ sys_config_fn
43
+ elsif File.exist? rel_config_fn
44
+ rel_config_fn
45
+ else
46
+ nil
47
+ end
48
+ }
49
+
50
+ options= OptionParser.new do |opts|
51
+ opts.banner= "usage: #{File.basename($0)} [options] screenplay.txt"
52
+ opts.separator('')
53
+ opts.separator(' Options:')
54
+ opts.on('-c', '--config FILE',
55
+ 'Load configuration from FILE',
56
+ "(default: #{conf[:config] || 'none'})") do |val|
57
+ conf[:config]= val
58
+ end
59
+ opts.on('-d', '--dump-pages', 'Print paginated screenplay to stdout') do |val|
60
+ conf[:dump_pages]= val
61
+ end
62
+ opts.on('--dump-paras', 'Print non-paginated paragraphs to stdout') do |val|
63
+ conf[:dump_paras]= val
64
+ end
65
+ opts.on('-h', '--help', 'Show this message') do
66
+ puts opts
67
+ exit
68
+ end
69
+ opts.on('-o', '--output FILE',
70
+ 'Set output FILE (default: screenplay.pdf)') do |val|
71
+ conf[:outfile]= val
72
+ end
73
+ opts.on('--paginate', 'Stop after pagination') do |val|
74
+ conf[:paginate]= val
75
+ end
76
+ opts.on('--paper FILE',
77
+ 'Set backend to FILE', "(default: #{conf[:paper]})") do |val|
78
+ conf[:paper]= val
79
+ end
80
+ opts.on('--parse', 'Stop after parsing') do |val|
81
+ conf[:parse]= val
82
+ end
83
+ opts.on('-v', '--verbose', 'Print working info to stderr') do |val|
84
+ conf[:verbose]= val
85
+ end
86
+ opts.on_tail('')
87
+ opts.on_tail(' Examples:',
88
+ " #{File.basename($0)} screenplay.txt",
89
+ " #{File.basename($0)} -o finaldraft.pdf screenplay.txt")
90
+ end
91
+
92
+ begin
93
+ options.parse!
94
+ raise OptionParser::ParseError unless ARGV.size == 1
95
+ rescue OptionParser::ParseError
96
+ puts options
97
+ exit
98
+ end
99
+
100
+ if conf[:config].nil?
101
+ abort "error: No configuration file found. Reinstall #{Eleanor::NAME} " \
102
+ "or load a configuration file with --config."
103
+ end
104
+
105
+ begin
106
+ require conf[:paper]
107
+ rescue LoadError
108
+ abort "error: Could not load backend. The string you specify will be " \
109
+ "passed to 'require'."
110
+ end
111
+ Eleanor.load_config(conf[:config])
112
+ infile= ARGV.shift
113
+ screenplay= Eleanor.parse(infile)
114
+
115
+ if screenplay
116
+ $stderr.puts "parsing complete" if conf[:verbose]
117
+ puts screenplay.to_s(false) if conf[:dump_paras]
118
+ exit if conf[:parse]
119
+ screenplay.paginate!
120
+ $stderr.puts "pagination complete" if conf[:verbose]
121
+ puts screenplay if conf[:dump_pages]
122
+ exit if conf[:paginate]
123
+ screenplay.write_to_paper!
124
+ screenplay.save_paper(conf[:outfile], infile)
125
+ else
126
+ abort 'error: parsing failed'
127
+ end
@@ -0,0 +1,165 @@
1
+ # This is Eleanor's default configuration file. It's written in YAML.
2
+ # You shouldn't modify it. Instead, pass your own to Eleanor's command line
3
+ # with the --config option. Or, for a more permanent solution, create your own
4
+ # file $HOME/.eleanorrc, where $HOME is the output of
5
+ #
6
+ # ruby -e "p ENV['HOME']"
7
+ #
8
+ # Eleanor will use that file instead.
9
+
10
+ ---
11
+ Screenplay:
12
+ char_spacing: -0.195.points
13
+ font: Courier
14
+ font_size: 12.points
15
+ line_height_points: 12
16
+
17
+ Page:
18
+ header: |
19
+ @page_no == 1 ? @screenplay.title : nil
20
+ header_margin_top: 0.5.inches
21
+ height: 11.inches
22
+ margin_bottom: 1.inches
23
+ margin_top: 1.inches
24
+ page_number_display: |
25
+ @page_no > 1 ? "#@page_no." : nil
26
+ page_number_margin_right: 1.25.inches
27
+ page_number_margin_top: 0.5.inches
28
+ width: 8.5.inches
29
+
30
+ TitlePage:
31
+ margin_bottom: 1.5.inches
32
+ margin_left: 1.inches
33
+ margin_top: 2.5.inches
34
+
35
+ Paragraph:
36
+ can_break_across_pages: false
37
+ align: left
38
+ keep_with_nexts: []
39
+ min_orphan_lines_allowed: 2
40
+ min_orphan_sentences_allowed: 2
41
+ min_widow_lines_allowed: 2
42
+ min_widow_sentences_allowed: 2
43
+
44
+ Action:
45
+ can_break_across_pages: true
46
+ keep_with_nexts: [Insert]
47
+ limit_to_one_line: false
48
+ margin_bottom: 1.lines
49
+ margin_left: 1.5.inches
50
+ margin_top: |
51
+ if @is_first_on_page
52
+ (@split_state == :widow ? -1 : 0).lines
53
+ else
54
+ 1.lines
55
+ end
56
+ width: 6.inches
57
+
58
+ CharacterCue:
59
+ continuation_modifier: CONT'D
60
+ keep_with_nexts: [Dialog, Parenthetical]
61
+ limit_to_one_line: true
62
+ margin_bottom: 0.lines
63
+ margin_left: 3.5.inches
64
+ margin_top: |
65
+ if @is_first_on_page
66
+ (@split_state == :widow ? -1 : 0).lines
67
+ else
68
+ 1.lines
69
+ end
70
+ widow_modifier: CONT'D
71
+ width: 3.75.inches
72
+
73
+ Dialog:
74
+ can_break_across_pages: true
75
+ keep_with_nexts: |
76
+ next_para.is_a?(Parenthetical) && @sentences.size == 1
77
+ limit_to_one_line: false
78
+ margin_bottom: 0.lines
79
+ margin_left: 2.5.inches
80
+ margin_top: 0.lines
81
+ width: 3.5.inches
82
+
83
+ Insert:
84
+ limit_to_one_line: false
85
+ margin_bottom: 1.lines
86
+ margin_left: 2.5.inches
87
+ margin_top: 1.lines
88
+ width: 3.5.inches
89
+
90
+ MontageHeading:
91
+ keep_with_nexts: [MontageItem]
92
+ limit_to_one_line: true
93
+ margin_bottom: 1.lines
94
+ margin_left: 1.5.inches
95
+ margin_top: |
96
+ (@is_first_on_page ? 0 : 2).lines
97
+ width: 6.inches
98
+
99
+ MontageItem:
100
+ limit_to_one_line: false
101
+ margin_bottom: 1.lines
102
+ margin_left: 1.5.inches
103
+ margin_top: |
104
+ (@is_first_on_page ? 0 : 1).lines
105
+ width: 6.inches
106
+
107
+ More:
108
+ limit_to_one_line: true
109
+ margin_bottom: 0.lines
110
+ margin_left: 3.5.inches
111
+ margin_top: 0.lines
112
+ text: (MORE)
113
+ width: 2.5.inches
114
+
115
+ Parenthetical:
116
+ keep_with_nexts: [Dialog]
117
+ limit_to_one_line: false
118
+ margin_bottom: 0.lines
119
+ margin_left: 2.9.inches
120
+ margin_top: 0.lines
121
+ width: 2.5.inches
122
+
123
+ SceneHeading:
124
+ keep_with_nexts: [Action, CharacterCue]
125
+ limit_to_one_line: true
126
+ margin_bottom: 1.lines
127
+ margin_left: 1.5.inches
128
+ margin_top: |
129
+ if defined?(prev_para) &&
130
+ (prev_para.is_a?(Transition) ||
131
+ (prev_para.is_a?(SlugLine) &&
132
+ /BEGIN FLASHBACK/i =~ prev_para.input_line))
133
+ 1.lines
134
+ else
135
+ (@is_first_on_page ? 0 : 2).lines
136
+ end
137
+ width: 6.inches
138
+
139
+ SlugLine:
140
+ keep_with_nexts: |
141
+ case next_para
142
+ when Action, Insert
143
+ true
144
+ when SceneHeading
145
+ /BEGIN FLASHBACK/i =~ @input_line ? true : false
146
+ else
147
+ false
148
+ end
149
+ limit_to_one_line: true
150
+ margin_bottom: 1.lines
151
+ margin_left: 1.5.inches
152
+ margin_top: |
153
+ (@is_first_on_page ? 0 : 1).lines
154
+ width: 6.inches
155
+
156
+ Transition:
157
+ align: |
158
+ /FADE IN/i =~ @input_line ? 'left' : 'right'
159
+ limit_to_one_line: true
160
+ margin_bottom: 1.lines
161
+ margin_left: 1.5.inches
162
+ margin_right: 1.25.inches
163
+ margin_top: |
164
+ (@is_first_on_page ? 0 : 1).lines
165
+ width: 1.63.inches
@@ -0,0 +1,167 @@
1
+
2
+ _A TALE OF NON SEQUITURS_
3
+ Fenwick Stufflebeam
4
+ 123 Millicent Kenton Lane
5
+ Hollywood, CA 90210
6
+ (555) 555-1337
7
+ fstufflebeam@hmail.com
8
+
9
+ FADE IN:
10
+
11
+ EXT. FOREST CLEARING - NIGHT
12
+
13
+ A clear, starry night. A milky full moon hangs high in the sky. Somewhere an owl hoots.
14
+
15
+ The bushes rustle. A dirtied girl pushes her way through the greenery, leaves and twigs slapping her face. Her name is ELEANOR. She carries a laptop computer under her arm.
16
+
17
+ ELEANOR
18
+ (calling)
19
+ Why! _Oh, why_!
20
+
21
+ Crickets. Eleanor sits on a nearby tree stump, head on hands.
22
+
23
+ Suddenly a tiny little man with shoulder-length brown hair scampers out of the trees. He is WHY THE LUCKY STIFF. He has a high-pitched voice, as if he has been inhaling helium.
24
+
25
+ WHY THE LUCKY STIFF
26
+ Here I am!
27
+
28
+ ELEANOR
29
+ Oh, thank God.
30
+
31
+ Why the Lucky Stiff jumps up on Eleanor's knee and produces a tiny flute. He plays a tune as he dances a little jig.
32
+
33
+ WHY THE LUCKY STIFF
34
+ Reese's Pieces and Old Navy fleeces! Norway has rakfisk but Finland has cheeses!
35
+
36
+ ELEANOR
37
+ Uh, OK.
38
+ (opening her laptop)
39
+ Listen, could you tell me how to use this thing?
40
+
41
+ WHY THE LUCKY STIFF
42
+ Ding dong!
43
+
44
+ He scurries to a tree and beckons Eleanor to follow.
45
+
46
+ WHY THE LUCKY STIFF
47
+ (pointing at tree)
48
+ _Rules_ here there be!
49
+
50
+ ELEANOR
51
+ Are you going to keep talking like that?
52
+
53
+ WHY THE LUCKY STIFF
54
+ Creamy ground beef!
55
+
56
+ With his little hand he pulls back a bough to reveal a carving on the trunk that reads:
57
+
58
+ "Two blank lines before scene headings and montages. One blank line before all else except dialogs and parentheticals. Spaces before character cues, dialog, parentheticals, transitions, inserts. No newlines in paragraphs. Two spaces between sentences."
59
+
60
+ ELEANOR
61
+ I don't understand.
62
+
63
+ WHY THE LUCKY STIFF
64
+ Plain text! Whoozits.
65
+
66
+ ELEANOR
67
+ What?
68
+
69
+ WHY THE LUCKY STIFF
70
+ You type, you type. The words flow like a sinking sun in a bathtub full of green jell-o.
71
+
72
+ He hops onto Eleanor's computer and by dancing on its keys types all that has transpired before this moment, in the format prescribed by the tree. Then he runs the command:
73
+
74
+ "ruby eleanor example.txt"
75
+
76
+ A beautiful PDF appears on Eleanor's computer.
77
+
78
+ ELEANOR
79
+ Oh!
80
+
81
+ SUDDENLY, WHY THE LUCKY STIFF
82
+
83
+ turns on his heels and sprints into the trees.
84
+
85
+ ELEANOR
86
+
87
+ drops her laptop in the commotion but picks it up and follows in hot pursuit deep into the woods.
88
+
89
+ ELEANOR'S P.O.V. - TREE BRANCHES
90
+
91
+ slap her in the face.
92
+
93
+ ELEANOR
94
+ (calling)
95
+ I'm not writing an action movie! This is supposed to be a quirky independent!
96
+
97
+
98
+ SERIES OF SHOTS - ELEANOR CHASES WHY THE LUCKY STIFF
99
+
100
+ A) Dodging branches and roots in the forest.
101
+
102
+ B) Trudging through a thick swamp.
103
+
104
+ C) Jumping across rooftops in a large city as cars sit stuck in traffic below.
105
+
106
+ D) Back into the dark forest.
107
+
108
+ DISSOLVE TO:
109
+
110
+
111
+ INT. HOLLOW TREE - NIGHT
112
+
113
+ A storybook gnomish home. Eleanor stumbles in, out of breath. Why the Lucky Stiff sits in a tiny rocking chair next to the fireplace, smoking a long pipe.
114
+
115
+ ELEANOR
116
+ (wheezing)
117
+ Jesus.
118
+ (pausing to look around)
119
+ So this is where you live.
120
+
121
+ WHY THE LUCKY STIFF
122
+ Here I be. Tinkle tops and lemon drops.
123
+
124
+ ELEANOR
125
+ Look, I have more questions.
126
+
127
+ WHY THE LUCKY STIFF
128
+ Let me tell you a story.
129
+
130
+ BEGIN FLASHBACK:
131
+
132
+
133
+ INT. PIGGLY WIGGLY - DAY
134
+
135
+ Why the Lucky Stiff pushes a diminutive shopping cart.
136
+
137
+ WHY THE LUCKY STIFF
138
+ (to himself)
139
+ Crackers. Soy beans. Hamburger patties. Sunshine rainbows and kitty cat kisses. Red-letter bibles and hose for the missus. Hey ho, yeah? What's all this, now? Bean sprouts from China and milk from a cow.
140
+
141
+ END FLASHBACK.
142
+
143
+
144
+ INT. HOLLOW TREE - NIGHT
145
+
146
+ Eleanor is exasperated.
147
+
148
+ ELEANOR
149
+ You're a nice guy, and you sure do know a lot, but I can't understand anything you say.
150
+
151
+ WHY THE LUCKY STIFF
152
+ Hey, but look! My dialog was split in twain!
153
+
154
+ ELEANOR
155
+ No, it wasn't.
156
+
157
+ WHY THE LUCKY STIFF
158
+ No, no, no, not in the plain text. In the PDF, yo!
159
+
160
+ ELEANOR
161
+ But I haven't written anything.
162
+
163
+ Why the Lucky Stiff pads over to Eleanor, who places her computer on the ground. He types in everything that has transpired so far except for what he had typed previously.
164
+
165
+ INSERT - ELEANOR'S COMPUTER SCREEN, A BEAUTIFUL PDF
166
+
167
+ FADE OUT.