html2fortitude 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 +10 -0
- data/.rspec-local +4 -0
- data/.travis.yml +16 -0
- data/.yardopts +1 -0
- data/Gemfile +5 -0
- data/MIT-LICENSE +38 -0
- data/README.md +97 -0
- data/Rakefile +29 -0
- data/bin/html2fortitude +7 -0
- data/html2fortitude.gemspec +31 -0
- data/lib/html2fortitude.rb +6 -0
- data/lib/html2fortitude/html.rb +755 -0
- data/lib/html2fortitude/html/erb.rb +156 -0
- data/lib/html2fortitude/run.rb +103 -0
- data/lib/html2fortitude/source_template.rb +93 -0
- data/lib/html2fortitude/version.rb +3 -0
- data/spec/helpers/global_helper.rb +6 -0
- data/spec/helpers/html2fortitude_result.rb +71 -0
- data/spec/helpers/standard_helper.rb +70 -0
- data/spec/system/basic_system_spec.rb +13 -0
- data/spec/system/command_line_spec.rb +411 -0
- data/spec/system/erb_system_spec.rb +208 -0
- data/spec/system/needs_system_spec.rb +73 -0
- data/spec/system/options_system_spec.rb +43 -0
- data/spec/system/other_stuff_system_spec.rb +39 -0
- data/spec/system/rails_system_spec.rb +9 -0
- data/spec/system/tags_system_spec.rb +252 -0
- data/spec/system/text_system_spec.rb +106 -0
- data/test/erb_test.rb +546 -0
- data/test/html2fortitude_test.rb +424 -0
- data/test/jruby/erb_test.rb +39 -0
- data/test/jruby/html2fortitude_test.rb +72 -0
- data/test/test_helper.rb +22 -0
- metadata +238 -0
@@ -0,0 +1,156 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require 'erubis'
|
3
|
+
require 'ruby_parser'
|
4
|
+
|
5
|
+
module Html2fortitude
|
6
|
+
class HTML
|
7
|
+
# A class for converting ERB code into a format that's easier
|
8
|
+
# for the {Html2fortitude::HTML} Nokogiri-based parser to understand.
|
9
|
+
#
|
10
|
+
# Uses [Erubis](http://www.kuwata-lab.com/erubis)'s extensible parsing powers
|
11
|
+
# to parse the ERB in a reliable way,
|
12
|
+
# and [ruby_parser](http://parsetree.rubyforge.org/)'s Ruby knowledge
|
13
|
+
# to figure out whether a given chunk of Ruby code starts a block or not.
|
14
|
+
#
|
15
|
+
# The ERB tags are converted to HTML tags in the following way.
|
16
|
+
# `<% ... %>` is converted into `<fortitude_silent> ... </fortitude_silent>`.
|
17
|
+
# `<%= ... %>` is converted into `<fortitude_loud> ... </fortitude_loud>`.
|
18
|
+
# `<%== ... %>` is converted into `<fortitude_loud raw=raw> ... </fortitude_loud>`.
|
19
|
+
# Finally, if either of these opens a Ruby block,
|
20
|
+
# `<fortitude_block> ... </fortitude_block>` will wrap the entire contents of the block -
|
21
|
+
# that is, everything that should be indented beneath the previous silent or loud tag.
|
22
|
+
class ERB < Erubis::Basic::Engine
|
23
|
+
# Compiles an ERB template into a HTML document containing `fortitude_*` tags.
|
24
|
+
#
|
25
|
+
# @param template [String] The ERB template
|
26
|
+
# @return [String] The output document
|
27
|
+
# @see Html2fortitude::HTML::ERB
|
28
|
+
def self.compile(template)
|
29
|
+
new(template).src
|
30
|
+
end
|
31
|
+
|
32
|
+
# The ERB-to-Fortitudeized-HTML conversion has no preamble.
|
33
|
+
def add_preamble(src); end
|
34
|
+
|
35
|
+
# The ERB-to-Fortitudeized-HTML conversion has no postamble.
|
36
|
+
def add_postamble(src); end
|
37
|
+
|
38
|
+
# Concatenates the text onto the source buffer.
|
39
|
+
#
|
40
|
+
# @param src [String] The source buffer
|
41
|
+
# @param text [String] The raw text to add to the buffer
|
42
|
+
def add_text(src, text)
|
43
|
+
src << text
|
44
|
+
end
|
45
|
+
|
46
|
+
# Concatenates a silent Ruby statement onto the source buffer.
|
47
|
+
# This uses the `<fortitude_silent>` tag,
|
48
|
+
# and may close and/or open a Ruby block with the `<fortitude_block>` tag.
|
49
|
+
#
|
50
|
+
# In particular, a block is closed if this statement is some form of `end`,
|
51
|
+
# opened if it's a block opener like `do`, `if`, or `begin`,
|
52
|
+
# and both closed and opened if it's a mid-block keyword
|
53
|
+
# like `else` or `when`.
|
54
|
+
#
|
55
|
+
# @param src [String] The source buffer
|
56
|
+
# @param code [String] The Ruby statement to add to the buffer
|
57
|
+
def add_stmt(src, code)
|
58
|
+
src << '</fortitude_block>' if block_closer?(code) || mid_block?(code)
|
59
|
+
src << '<fortitude_silent>' << h(code) << '</fortitude_silent>' unless code.strip == "end"
|
60
|
+
src << '<fortitude_block>' if block_opener?(code) || mid_block?(code)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Concatenates a Ruby expression that's printed to the document
|
64
|
+
# onto the source buffer.
|
65
|
+
# This uses the `<fortitude:silent>` tag,
|
66
|
+
# and may open a Ruby block with the `<fortitude:block>` tag.
|
67
|
+
# An expression never closes a block.
|
68
|
+
#
|
69
|
+
# @param src [String] The source buffer
|
70
|
+
# @param code [String] The Ruby expression to add to the buffer
|
71
|
+
def add_expr_literal(src, code)
|
72
|
+
src << '<fortitude_loud>' << h(code) << '</fortitude_loud>'
|
73
|
+
src << '<fortitude_block>' if block_opener?(code)
|
74
|
+
end
|
75
|
+
|
76
|
+
def add_expr_escaped(src, code)
|
77
|
+
src << "<fortitude_loud raw=raw>" << h(code) << "</fortitude_loud>"
|
78
|
+
end
|
79
|
+
|
80
|
+
# `html2fortitude` doesn't support debugging expressions.
|
81
|
+
def add_expr_debug(src, code)
|
82
|
+
# TODO ageweke
|
83
|
+
# raise Haml::Error.new("html2haml doesn't support debugging expressions.")
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
# HTML-escaped some text (in practice, always Ruby code).
|
89
|
+
# A utility method.
|
90
|
+
#
|
91
|
+
# @param text [String] The text to escape
|
92
|
+
# @return [String] The escaped text
|
93
|
+
def h(text)
|
94
|
+
CGI.escapeHTML(text)
|
95
|
+
end
|
96
|
+
|
97
|
+
# Returns whether the code is valid Ruby code on its own.
|
98
|
+
#
|
99
|
+
# @param code [String] Ruby code to check
|
100
|
+
# @return [Boolean]
|
101
|
+
def valid_ruby?(code)
|
102
|
+
RubyParser.new.parse(code)
|
103
|
+
rescue Racc::ParseError, RubyParser::SyntaxError
|
104
|
+
false
|
105
|
+
end
|
106
|
+
|
107
|
+
# Returns whether the code has any content
|
108
|
+
# This is used to test whether lines have been removed by erubis, such as comments
|
109
|
+
#
|
110
|
+
# @param code [String] Ruby code to check
|
111
|
+
# @return [Boolean]
|
112
|
+
def has_code?(code)
|
113
|
+
return false if code == "\n"
|
114
|
+
return false if valid_ruby?(code) == nil
|
115
|
+
true
|
116
|
+
end
|
117
|
+
|
118
|
+
# Checks if a string of Ruby code opens a block.
|
119
|
+
# This could either be something like `foo do |a|`
|
120
|
+
# or a keyword that requires a matching `end`
|
121
|
+
# like `if`, `begin`, or `case`.
|
122
|
+
#
|
123
|
+
# @param code [String] Ruby code to check
|
124
|
+
# @return [Boolean]
|
125
|
+
def block_opener?(code)
|
126
|
+
return unless has_code?(code)
|
127
|
+
valid_ruby?(code + "\nend") ||
|
128
|
+
valid_ruby?(code + "\nwhen foo\nend")
|
129
|
+
end
|
130
|
+
|
131
|
+
# Checks if a string of Ruby code closes a block.
|
132
|
+
# This is always `end` followed optionally by some method calls.
|
133
|
+
#
|
134
|
+
# @param code [String] Ruby code to check
|
135
|
+
# @return [Boolean]
|
136
|
+
def block_closer?(code)
|
137
|
+
return unless has_code?(code)
|
138
|
+
valid_ruby?("begin\n" + code)
|
139
|
+
end
|
140
|
+
|
141
|
+
# Checks if a string of Ruby code comes in the middle of a block.
|
142
|
+
# This could be a keyword like `else`, `rescue`, or `when`,
|
143
|
+
# or even `end` with a method call that takes a block.
|
144
|
+
#
|
145
|
+
# @param code [String] Ruby code to check
|
146
|
+
# @return [Boolean]
|
147
|
+
def mid_block?(code)
|
148
|
+
return unless has_code?(code)
|
149
|
+
return if valid_ruby?(code)
|
150
|
+
valid_ruby?("if foo\n#{code}\nend") || # else, elsif
|
151
|
+
valid_ruby?("begin\n#{code}\nend") || # rescue, ensure
|
152
|
+
valid_ruby?("case foo\n#{code}\nend") # when
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'trollop'
|
2
|
+
require 'find'
|
3
|
+
require 'html2fortitude/source_template'
|
4
|
+
|
5
|
+
module Html2fortitude
|
6
|
+
class Run
|
7
|
+
def initialize(argv)
|
8
|
+
@argv = argv
|
9
|
+
end
|
10
|
+
|
11
|
+
def run!
|
12
|
+
parse_arguments!
|
13
|
+
|
14
|
+
for_each_input_file do |name_and_block|
|
15
|
+
name = name_and_block[:name]
|
16
|
+
block = name_and_block[:block]
|
17
|
+
|
18
|
+
contents = nil
|
19
|
+
block.call { |io| contents = io.read }
|
20
|
+
|
21
|
+
effective_options = trollop_options.select do |key, value|
|
22
|
+
%w{output class_name class_base superclass method assigns do_end new_style_hashes}.include?(key.to_s)
|
23
|
+
end
|
24
|
+
|
25
|
+
source_template = Html2fortitude::SourceTemplate.new(name, contents, effective_options)
|
26
|
+
source_template.write_transformed_content!
|
27
|
+
|
28
|
+
unless @argv.include?("-")
|
29
|
+
puts "#{source_template.filename} -> #{source_template.output_filename} (#{source_template.line_count} lines)"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
def for_each_input_file(&block)
|
36
|
+
@argv.each do |file_or_directory|
|
37
|
+
if file_or_directory == '-'
|
38
|
+
block.call({ :name => '-', :block => lambda { |&block| block.call($stdin) } })
|
39
|
+
next
|
40
|
+
end
|
41
|
+
|
42
|
+
file_or_directory = File.expand_path(file_or_directory)
|
43
|
+
raise Errno::ENOENT, "No such file or directory: #{file_or_directory}" unless File.exist?(file_or_directory)
|
44
|
+
|
45
|
+
files = [ ]
|
46
|
+
if File.directory?(file_or_directory)
|
47
|
+
Find.find(file_or_directory) do |f|
|
48
|
+
f = File.expand_path(f, file_or_directory)
|
49
|
+
files << f if File.file?(f) && f =~ /\.r?html/
|
50
|
+
end
|
51
|
+
else
|
52
|
+
files << file_or_directory
|
53
|
+
end
|
54
|
+
|
55
|
+
files.each do |file|
|
56
|
+
block.call(:name => file, :block => lambda { |&block| File.open(file, &block) })
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def parse_arguments!
|
62
|
+
trollop_options
|
63
|
+
end
|
64
|
+
|
65
|
+
def trollop_options
|
66
|
+
@trollop_parser ||= Trollop::Parser.new do
|
67
|
+
version "html2fortitude version #{Html2fortitude::VERSION}"
|
68
|
+
banner <<-EOS
|
69
|
+
html2fortitude transforms HTML source files (with or without ERb embedded)
|
70
|
+
into Fortitude (https://github.com/ageweke/fortitude) source code.
|
71
|
+
|
72
|
+
Usage:
|
73
|
+
html2fortitude [options] file|directory [file|directory...]
|
74
|
+
where [options] are:
|
75
|
+
EOS
|
76
|
+
|
77
|
+
opt :output, "Output file or directory", :type => String
|
78
|
+
|
79
|
+
opt :class_name, "Class name for created Fortitude class", :type => String
|
80
|
+
opt :class_base, "Base directory for input files (e.g., my_rails_app/app) to use when --class-name is not specified", :type => String, :short => 'b'
|
81
|
+
opt :superclass, "Name of the class to inherit the output class from", :type => String, :default => 'Fortitude::Widget::Html5'
|
82
|
+
|
83
|
+
opt :method, "Name of method to write in widget (default 'content')", :type => String, :default => 'content'
|
84
|
+
opt :assigns, %{Method for using assigns passed to the widget:
|
85
|
+
needs_defaulted_to_nil: (default) standard Fortitude 'needs', but with a default of 'nil', so all needs are optional
|
86
|
+
required_needs: standard Fortitude 'needs', no default; widget will not render without all needs specified (dangerous)
|
87
|
+
instance_variables: Ruby instance variables; requires that a base class of the widget sets 'use_instance_variables_for_assigns true'
|
88
|
+
no_needs: Omit a 'needs' declaration entirely; requires that a base class sets 'extra_assigns :use'},
|
89
|
+
:type => String, :default => 'needs_defaulted_to_nil'
|
90
|
+
|
91
|
+
opt :do_end, "Use do ... end for blocks passed to tag methods, not { ... } (does not affect blocks from ERb)", :type => :boolean
|
92
|
+
opt :new_style_hashes, "Use hash_style: ruby19 instead of :hash_style => :ruby_18", :type => :boolean
|
93
|
+
end
|
94
|
+
|
95
|
+
@trollop_options ||= begin
|
96
|
+
Trollop::with_standard_exception_handling(@trollop_parser) do
|
97
|
+
raise Trollop::HelpNeeded if @argv.empty? # show help screen
|
98
|
+
@trollop_parser.parse @argv
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'html2fortitude/html'
|
2
|
+
|
3
|
+
module Html2fortitude
|
4
|
+
class SourceTemplate
|
5
|
+
attr_reader :filename, :line_count
|
6
|
+
|
7
|
+
def initialize(filename, contents, options)
|
8
|
+
options.assert_valid_keys(:output, :class_name, :class_base, :superclass, :method, :assigns,
|
9
|
+
:do_end, :new_style_hashes)
|
10
|
+
|
11
|
+
@filename = filename
|
12
|
+
@contents = contents
|
13
|
+
@options = options
|
14
|
+
@line_count = @contents.split(/(\r|\n|\r\n)/).length
|
15
|
+
end
|
16
|
+
|
17
|
+
def write_transformed_content!
|
18
|
+
html_options = {
|
19
|
+
:class_name => output_class_name,
|
20
|
+
:superclass => options[:superclass],
|
21
|
+
:method => options[:method],
|
22
|
+
:assigns => options[:assigns],
|
23
|
+
:do_end => options[:do_end],
|
24
|
+
:new_style_hashes => options[:new_style_hashes]
|
25
|
+
}
|
26
|
+
|
27
|
+
html = HTML.new(contents, html_options).render
|
28
|
+
|
29
|
+
if output_filename == '-'
|
30
|
+
puts html
|
31
|
+
else
|
32
|
+
FileUtils.mkdir_p(File.dirname(output_filename))
|
33
|
+
File.open(output_filename, 'w') { |f| f << html }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def output_filename
|
38
|
+
if (! options[:output]) && (filename == "-")
|
39
|
+
"-"
|
40
|
+
elsif (! options[:output])
|
41
|
+
if filename =~ /^(.*)\.html\.erb$/i || filename =~ /^(.*)\.rhtml$/i
|
42
|
+
"#{$1}.rb"
|
43
|
+
else
|
44
|
+
"#{filename}.rb"
|
45
|
+
end
|
46
|
+
elsif File.directory?(options[:output])
|
47
|
+
File.join(File.expand_path(options[:output]), "#{output_class_name.underscore}.rb")
|
48
|
+
else
|
49
|
+
File.expand_path(options[:output])
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
attr_reader :contents, :options
|
55
|
+
|
56
|
+
def output_class_name
|
57
|
+
if options[:class_name]
|
58
|
+
options[:class_name]
|
59
|
+
else
|
60
|
+
cb = class_base
|
61
|
+
if filename.start_with?("#{cb}/")
|
62
|
+
out = filename[(cb.length + 1)..-1].camelize
|
63
|
+
out = $1 if out =~ %r{^(.*?)\.[^/]+$}i
|
64
|
+
out
|
65
|
+
else
|
66
|
+
raise %{You specified a class base using the -b command-line option:
|
67
|
+
#{class_base}
|
68
|
+
but the file you asked to parse is not underneath that directory:
|
69
|
+
#{filename}}
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def class_base
|
75
|
+
File.expand_path(options[:class_base] || infer_class_base)
|
76
|
+
end
|
77
|
+
|
78
|
+
def infer_class_base
|
79
|
+
if filename =~ %r{^(.*app)/views/.*$}
|
80
|
+
File.expand_path($1)
|
81
|
+
elsif filename == "-"
|
82
|
+
raise %{When converting standard input, you must specify a name for the output class
|
83
|
+
using the -c command-line option. (Otherwise, we have no way of knowing what to name this widget!)}
|
84
|
+
else
|
85
|
+
raise %{We can't figure out what the name of the widget class for this file should be:
|
86
|
+
#{filename}
|
87
|
+
You must either specify an explicit name for the class, using the -c command-line option, or
|
88
|
+
specify a base directory to infer the class name from, using the -b command-line option
|
89
|
+
(e.g., "-b my_rails_app/app").}
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
class Html2FortitudeResult
|
2
|
+
attr_reader :needs, :class_name, :superclass, :method_name
|
3
|
+
|
4
|
+
def initialize(text)
|
5
|
+
lines = text.split(/[\r\n]/)
|
6
|
+
if lines.shift =~ /^\s*class\s*(\S+)\s+<\s+(\S+)\s*$/i
|
7
|
+
@class_name = $1
|
8
|
+
@superclass = $2
|
9
|
+
else
|
10
|
+
raise "Can't find 'class' declaration in: #{text}"
|
11
|
+
end
|
12
|
+
|
13
|
+
@needs = { }
|
14
|
+
|
15
|
+
lines.shift while lines[0] =~ /^\s*$/i
|
16
|
+
|
17
|
+
while lines[0] =~ /^\s*needs\s*(.*?)\s*$/i
|
18
|
+
need_name = $1
|
19
|
+
need_value = nil
|
20
|
+
|
21
|
+
if need_name =~ /^(.*?)\s*=>\s*(.*?)\s*$/i
|
22
|
+
need_name = $1
|
23
|
+
need_value = $2
|
24
|
+
end
|
25
|
+
|
26
|
+
@needs[need_name] = need_value
|
27
|
+
|
28
|
+
lines.shift
|
29
|
+
end
|
30
|
+
|
31
|
+
lines.shift while lines[0] =~ /^\s*$/i
|
32
|
+
|
33
|
+
if lines[0] =~ /^\s+def\s+(\S+)\s*$/i
|
34
|
+
@method_name = $1
|
35
|
+
lines.shift
|
36
|
+
else
|
37
|
+
raise "Can't find 'def' in: #{text}"
|
38
|
+
end
|
39
|
+
|
40
|
+
lines.pop while lines[-1] =~ /^\s*$/i
|
41
|
+
if lines[-1] =~ /^\s*end\s*$/i
|
42
|
+
lines.pop
|
43
|
+
else
|
44
|
+
raise "Can't find last 'end' in: #{text}"
|
45
|
+
end
|
46
|
+
|
47
|
+
lines.pop while lines[-1] =~ /^\s*$/i
|
48
|
+
if lines[-1] =~ /^\s*end\s*$/i
|
49
|
+
lines.pop
|
50
|
+
else
|
51
|
+
raise "Can't find last 'end' in: #{text}"
|
52
|
+
end
|
53
|
+
|
54
|
+
@content_lines = lines
|
55
|
+
@content_lines = @content_lines.map do |content_line|
|
56
|
+
content_line = content_line.rstrip
|
57
|
+
if content_line[0..3] == ' '
|
58
|
+
content_line[4..-1]
|
59
|
+
else
|
60
|
+
content_line
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def content_text
|
66
|
+
@content_lines.join("\n")
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
attr_reader :text
|
71
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'helpers/html2fortitude_result'
|
2
|
+
require 'html2fortitude/html'
|
3
|
+
|
4
|
+
module StandardHelper
|
5
|
+
def default_html_options
|
6
|
+
{
|
7
|
+
:class_name => "SpecClass",
|
8
|
+
:superclass => "Fortitude::Widget::Html5",
|
9
|
+
:method => "content",
|
10
|
+
:assigns => :needs_defaulted_to_nil,
|
11
|
+
:do_end => false,
|
12
|
+
:new_style_hashes => false
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
def h2f(input, options = { })
|
17
|
+
Html2FortitudeResult.new(Html2fortitude::HTML.new(input, default_html_options.merge(options)).render)
|
18
|
+
end
|
19
|
+
|
20
|
+
def h2f_content(input, options = { })
|
21
|
+
h2f(input, options).content_text
|
22
|
+
end
|
23
|
+
|
24
|
+
def h2f_from(filename)
|
25
|
+
Html2FortitudeResult.new(get(filename))
|
26
|
+
end
|
27
|
+
|
28
|
+
def invoke(*args)
|
29
|
+
cmd = "#{binary_path} #{args.join(" ")} 2>&1"
|
30
|
+
output = `#{cmd}`
|
31
|
+
unless $?.success?
|
32
|
+
raise "Invocation failed: ran: #{cmd}\nin: #{Dir.pwd}\nand got: #{$?.inspect}\nwith output:\n#{output}"
|
33
|
+
end
|
34
|
+
output
|
35
|
+
end
|
36
|
+
|
37
|
+
def splat!(filename, data)
|
38
|
+
FileUtils.mkdir_p(File.dirname(filename))
|
39
|
+
File.open(filename, 'w') { |f| f << data }
|
40
|
+
end
|
41
|
+
|
42
|
+
def get(filename)
|
43
|
+
raise Errno::ENOENT, "No such file: #{filename.inspect}" unless File.file?(filename)
|
44
|
+
File.read(filename).strip
|
45
|
+
end
|
46
|
+
|
47
|
+
def with_temp_directory(name, &block)
|
48
|
+
directory = File.join(temp_directory_base, name)
|
49
|
+
FileUtils.rm_rf(directory) if File.exist?(directory)
|
50
|
+
FileUtils.mkdir_p(directory)
|
51
|
+
Dir.chdir(directory, &block)
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
def temp_directory_base
|
56
|
+
@temp_directory_base ||= begin
|
57
|
+
out = File.join(gem_root, 'tmp', 'specs')
|
58
|
+
FileUtils.mkdir_p(out)
|
59
|
+
out
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def gem_root
|
64
|
+
@gem_root ||= File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
|
65
|
+
end
|
66
|
+
|
67
|
+
def binary_path
|
68
|
+
@binary_path ||= File.join(gem_root, 'bin', 'html2fortitude')
|
69
|
+
end
|
70
|
+
end
|