epubforge 0.0.10 → 0.0.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (135) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +17 -10
  3. data/VERSION +1 -1
  4. data/bin/epubforge +1 -1
  5. data/config/actions/epub.rb +50 -0
  6. data/config/actions/forge.rb +34 -13
  7. data/config/actions/git.rb +106 -0
  8. data/config/actions/help.rb +13 -13
  9. data/config/actions/html.rb +33 -0
  10. data/config/actions/mobi.rb +60 -0
  11. data/config/actions/new.rb +182 -0
  12. data/config/actions/word_count.rb +26 -24
  13. data/config/{actions → actions_to_ignore}/generate.rb +1 -1
  14. data/config/{actions → actions_to_ignore}/generate_chapter.rb +0 -0
  15. data/config/{actions → actions_to_ignore}/git_backup.rb +2 -2
  16. data/config/{actions → actions_to_ignore}/globals.rb +1 -1
  17. data/config/{actions → actions_to_ignore}/kindle.rb +3 -3
  18. data/config/{actions → actions_to_ignore}/local_action.rb +1 -1
  19. data/config/{actions → actions_to_ignore}/mobify.rb +3 -3
  20. data/config/actions_to_ignore/notes_to_epub.rb +19 -0
  21. data/config/actions_to_ignore/notes_to_kindle.rb +18 -0
  22. data/config/{actions → actions_to_ignore}/spell.rb +1 -1
  23. data/config/{actions → actions_to_ignore}/version.rb +3 -3
  24. data/config/{actions → actions_to_ignore}/wrap_scene_notes_in_hidden_div.rb +1 -1
  25. data/config/converters/epub_to_mobi.calibre.rb +8 -0
  26. data/config/converters/epub_to_mobi.kindlegen.rb +11 -0
  27. data/config/html_translators/default_kramdown.html_translator.rb +9 -0
  28. data/config/html_translators/default_markdown.html_translator.rb +10 -0
  29. data/config/html_translators/default_markdown_pandoc.html_translator.rb +10 -0
  30. data/config/html_translators/default_textile_pandoc.html_translator.rb +8 -0
  31. data/config/html_translators/default_xhtml.html_translator.rb +7 -0
  32. data/config/html_translators/fallback_html.html_translator.rb +9 -0
  33. data/config/html_translators/fallback_markdown.html_translator.rb +8 -0
  34. data/config/html_translators/fallback_textile.html_translator.rb +7 -0
  35. data/config/html_translators/fallback_txt.html_translator.rb +8 -0
  36. data/config/html_translators/fallback_unknown.html_translator.rb +7 -0
  37. data/lib/epubforge.rb +37 -82
  38. data/lib/{action/thor_action.rb → epubforge/action/action.rb} +89 -69
  39. data/lib/epubforge/action/action2.rb +109 -0
  40. data/lib/epubforge/action/action_definition.rb +62 -0
  41. data/lib/epubforge/action/actions_lookup.rb +45 -0
  42. data/lib/epubforge/action/chatterbox.rb +93 -0
  43. data/lib/{action → epubforge/action}/cli_command.rb +2 -2
  44. data/lib/{action → epubforge/action}/cli_sequence.rb +0 -0
  45. data/lib/{action → epubforge/action}/file_transformer.rb +0 -0
  46. data/lib/{action → epubforge/action}/hooks_interface.rb +2 -2
  47. data/lib/{action → epubforge/action}/run_description.rb +12 -9
  48. data/lib/{action → epubforge/action}/runner.rb +23 -24
  49. data/lib/{epub → epubforge/builder}/assets/asset.rb +1 -1
  50. data/lib/{epub → epubforge/builder}/assets/font.rb +1 -1
  51. data/lib/epubforge/builder/assets/html.rb +9 -0
  52. data/lib/{epub → epubforge/builder}/assets/image.rb +1 -1
  53. data/lib/epubforge/builder/assets/markdown.rb +9 -0
  54. data/lib/{epub → epubforge/builder}/assets/page.rb +12 -4
  55. data/lib/{epub → epubforge/builder}/assets/stylesheet.rb +1 -1
  56. data/lib/epubforge/builder/assets/textile.rb +9 -0
  57. data/lib/epubforge/builder/assets/xhtml.rb +9 -0
  58. data/lib/epubforge/builder/builder.rb +134 -0
  59. data/lib/{epub/builder.rb → epubforge/builder/epub.rb} +58 -161
  60. data/lib/epubforge/builder/html.rb +22 -0
  61. data/lib/epubforge/builder/packager.rb +16 -0
  62. data/lib/epubforge/core_extensions/array.rb +2 -0
  63. data/lib/{core_extensions → epubforge/core_extensions}/kernel.rb +0 -0
  64. data/lib/epubforge/core_extensions/nil_class.rb +2 -0
  65. data/lib/epubforge/core_extensions/object.rb +24 -0
  66. data/lib/{core_extensions → epubforge/core_extensions}/string.rb +1 -5
  67. data/lib/{custom_helpers.rb → epubforge/custom_helpers.rb} +0 -1
  68. data/lib/{errors.rb → epubforge/exceptions/errors.rb} +0 -0
  69. data/lib/{project → epubforge/project}/project.rb +23 -17
  70. data/lib/epubforge/utils/action_loader.rb +8 -0
  71. data/lib/epubforge/utils/class_loader.rb +102 -0
  72. data/lib/epubforge/utils/converter.rb +94 -0
  73. data/lib/{utils → epubforge/utils}/downloader.rb +0 -0
  74. data/lib/{utils → epubforge/utils}/file_orderer.rb +0 -0
  75. data/lib/epubforge/utils/file_path.rb +8 -0
  76. data/lib/epubforge/utils/html_translator.rb +126 -0
  77. data/lib/epubforge/utils/html_translator_queue.rb +113 -0
  78. data/lib/epubforge/utils/htmlizer.rb +61 -0
  79. data/lib/{utils → epubforge/utils}/misc.rb +0 -0
  80. data/lib/epubforge/utils/root_path.rb +8 -0
  81. data/lib/epubforge/utils/settings.rb +147 -0
  82. data/lib/epubforge/utils/template_evaluator.rb +7 -0
  83. data/templates/{default/book/afterword.markdown.template → project/book/afterword.markdown} +0 -0
  84. data/templates/project/book/chapter-%0000chapter%.markdown.template +4 -0
  85. data/templates/{default → project}/book/cover.xhtml.template +2 -2
  86. data/templates/{default/book/foreword.markdown.template → project/book/foreword.markdown} +0 -0
  87. data/templates/{default → project}/book/images/cover.png +0 -0
  88. data/templates/{default/book/stylesheets/stylesheet.css.template → project/book/stylesheets/stylesheet.css} +0 -0
  89. data/templates/project/book/title_page.markdown.template +5 -0
  90. data/templates/project/notes/character.%character.name_for_file%.markdown.template +15 -0
  91. data/templates/{default → project}/notes/images/cover.png +0 -0
  92. data/templates/{default/notes/stylesheets/stylesheet.css.template → project/notes/stylesheets/stylesheet.css} +0 -0
  93. data/templates/{default → project}/settings/actions/local_action.rb.example +1 -1
  94. data/templates/project/settings/config.rb.template +70 -0
  95. data/templates/project/settings/html_translators/example_translator.rb +29 -0
  96. data/templates/{default → project}/settings/wordcount.template +1 -1
  97. data/test/answers01.yml +30 -0
  98. data/test/helper.rb +62 -39
  99. data/test/misc/config.rb +5 -7
  100. data/test/test_epubforge.rb +18 -14
  101. data/test/{test_htmlizers.rb → test_html_translators.rb} +4 -8
  102. data/test/test_template_evaluator.rb +42 -0
  103. data/test/test_utils.rb +0 -11
  104. metadata +186 -189
  105. data/config/actions/gitify.rb +0 -72
  106. data/config/actions/init.rb +0 -138
  107. data/config/actions/notes_to_epub.rb +0 -18
  108. data/config/actions/notes_to_kindle.rb +0 -17
  109. data/config/htmlizers.rb +0 -70
  110. data/lib/action/actions_lookup.rb +0 -45
  111. data/lib/core_extensions/array.rb +0 -5
  112. data/lib/core_extensions/nil_class.rb +0 -5
  113. data/lib/core_extensions/object.rb +0 -5
  114. data/lib/epub/assets/html.rb +0 -8
  115. data/lib/epub/assets/markdown.rb +0 -8
  116. data/lib/epub/assets/textile.rb +0 -8
  117. data/lib/epub/assets/xhtml.rb +0 -8
  118. data/lib/epub/packager.rb +0 -16
  119. data/lib/utils/action_loader.rb +0 -7
  120. data/lib/utils/class_loader.rb +0 -102
  121. data/lib/utils/directory_builder.rb +0 -181
  122. data/lib/utils/file_path.rb +0 -152
  123. data/lib/utils/html_translator.rb +0 -100
  124. data/lib/utils/html_translator_queue.rb +0 -70
  125. data/lib/utils/htmlizer.rb +0 -92
  126. data/lib/utils/root_path.rb +0 -20
  127. data/lib/utils/settings.rb +0 -146
  128. data/lib/utils/template_evaluator.rb +0 -20
  129. data/templates/default/book/chapter-%i%.markdown.sequence +0 -4
  130. data/templates/default/book/title_page.markdown.template +0 -4
  131. data/templates/default/notes/character.named.markdown.template +0 -4
  132. data/templates/default/payload.rb +0 -65
  133. data/templates/default/settings/config.rb.form +0 -55
  134. data/templates/default/settings/htmlizers.rb +0 -0
  135. data/test/test_directory_builder.rb +0 -141
@@ -1,65 +1,80 @@
1
1
  module EpubForge
2
2
  module Action
3
3
  module SharedActionInterface
4
- def actions_lookup
5
- if self == ThorAction
6
- @actions_lookup ||= ActionsLookup.new
7
- else
8
- ThorAction.actions_lookup
9
- end
10
- end
4
+ # def actions_lookup
5
+ # if self == Action
6
+ # @actions_lookup ||= ActionsLookup.new
7
+ # else
8
+ # Action.actions_lookup
9
+ # end
10
+ # end
11
11
 
12
- def register_action_subclass( klass )
13
- if self == ThorAction
14
- @subclasses ||= []
15
- @subclasses = (@subclasses + [klass]).uniq
16
- else
17
- ThorAction.register_action_subclass( klass )
18
- end
19
- end
12
+ # def register_action_subclass( klass )
13
+ # if self == Action
14
+ # @subclasses ||= []
15
+ # @subclasses = (@subclasses + [klass]).uniq
16
+ # else
17
+ # Action.register_action_subclass( klass )
18
+ # end
19
+ # end
20
20
 
21
- def subclasses
22
- if self == ThorAction
23
- @subclasses
24
- else
25
- ThorAction.subclasses
26
- end
27
- end
21
+ # def subclasses
22
+ # if self == Action
23
+ # @subclasses
24
+ # else
25
+ # Action.subclasses
26
+ # end
27
+ # end
28
28
 
29
- def command_to_action_classes
30
- if self == ThorAction
31
- @command_klass_lookup ||= {}
32
- else
33
- ThorAction.command_to_action_classes
34
- end
35
- end
29
+ # def command_to_action_classes
30
+ # if self == Action
31
+ # @command_klass_lookup ||= {}
32
+ # else
33
+ # Action.command_to_action_classes
34
+ # end
35
+ # end
36
36
 
37
- def description( str = nil )
38
- @description = str if str
39
- @description
40
- end
37
+ get_and_set( :description )
38
+ # def description( str = nil )
39
+ # @description = str if str
40
+ # @description
41
+ # end
41
42
 
42
43
  # eventually replace description
43
44
  def desc( usage, description, options = {} )
45
+ verbose = defined?(EpubForge::Action::Character) && self == EpubForge::Action::Character
46
+ puts "--------------IN DESC()----------------" if verbose
47
+ puts self.method_options.inspect if verbose
44
48
  self.command_to_action_classes[usage] = self
45
49
  super( usage, description, options )
50
+ puts self.method_options.inspect if verbose
51
+ puts "--------------END DESC()----------------" if verbose
46
52
  end
47
53
 
48
- # TODO: Get rid of this
49
- def keywords( *args )
50
- if args.epf_blank?
51
- @keywords ||= []
52
- else
53
- @keywords = args.map(&:to_s)
54
- end
55
-
56
- @keywords
57
- end
54
+ # # TODO: Get rid of this
55
+ # def keywords( *args )
56
+ # if args.fwf_blank?
57
+ # @keywords ||= []
58
+ # else
59
+ # @keywords = args.map(&:to_s)
60
+ # end
61
+ #
62
+ # @keywords
63
+ # end
58
64
 
59
- def usage( str = nil )
60
- @usage = str if str
61
- @usage
62
- end
65
+ # If given one arg, sets keyword
66
+ # if given no args, fetches keyword
67
+ get_and_set( :keyword, :usage ) #
68
+ # def keyword( k = nil )
69
+ # @keyword = k unless k.nil?
70
+ # @keyword
71
+ # end
72
+ #
73
+ #
74
+ # def usage( str = nil )
75
+ # @usage = str if str
76
+ # @usage
77
+ # end
63
78
 
64
79
  def project_required?
65
80
  @project_required = true if @project_required.nil?
@@ -83,11 +98,11 @@ module EpubForge
83
98
  end
84
99
  end
85
100
 
86
- class ThorAction < Thor
87
- def self.inherited( subclass )
88
- self.register_action_subclass( subclass )
89
- subclass.include_standard_options
90
- end
101
+ class Action < Thor
102
+ # def self.inherited( subclass )
103
+ # self.register_action_subclass( subclass )
104
+ # subclass.include_standard_options
105
+ # end
91
106
 
92
107
  include Thor::Actions
93
108
  extend SharedActionInterface
@@ -102,6 +117,9 @@ module EpubForge
102
117
  ON_BLUE = Thor::Shell::Color::ON_BLUE
103
118
 
104
119
 
120
+
121
+
122
+
105
123
  protected
106
124
  def say_when_verbose( *args )
107
125
  say( *args ) if @verbose
@@ -142,9 +160,9 @@ module EpubForge
142
160
  end
143
161
 
144
162
  choice_text = ""
145
- choices.each_with_index{ |choice,i|
163
+ choices.each_with_index do |choice,i|
146
164
  choice_text << "\t\t#{i}) #{choice.first}\n"
147
- }
165
+ end
148
166
 
149
167
  selection = ask( "#{statement}\n\tChoices:\n#{choice_text}>>> ", BLUE )
150
168
  choices[selection.to_i].last
@@ -153,6 +171,8 @@ module EpubForge
153
171
  def ask_prettily( statement )
154
172
  ask( statement, BLUE )
155
173
  end
174
+
175
+
156
176
 
157
177
  # hope this doesn't break anything. Sure enough, it broke a lot of things.
158
178
  # def destination_root=( root )
@@ -160,16 +180,6 @@ module EpubForge
160
180
  # @destination_stack << (root ? root.fwf_filepath.expand : '')
161
181
  # end
162
182
 
163
- # Instead, use these instead of destination_root. Thor gets strings instead of
164
- # filepaths, like it wants, and I get filepaths instead of strings, like I want.
165
- def destination_root_filepath
166
- self.destination_root.fwf_filepath
167
- end
168
-
169
- def destination_root_filepath=(root)
170
- self.destination_root = root.to_s
171
- end
172
-
173
183
  def executable_installed?( name )
174
184
  name = name.to_sym
175
185
 
@@ -218,7 +228,7 @@ module EpubForge
218
228
  end
219
229
 
220
230
  def project_already_gitted?
221
- @project.target_dir.join( ".git" ).directory?
231
+ @project.root_dir.join( ".git" ).directory?
222
232
  end
223
233
 
224
234
  def quit_with_error( msg, errno = -1 )
@@ -227,12 +237,22 @@ module EpubForge
227
237
  end
228
238
 
229
239
  def before_start
230
- @project = @options[:project]
231
- @debug = @options[:debug]
232
- @help = @options[:help]
233
- @verbose = @options[:verbose]
240
+ variablize_options( :project, :debug, :help, :verbose )
241
+ # @project = @options[:project]
242
+ # @debug = @options[:debug]
243
+ # @help = @options[:help]
244
+ # @verbose = @options[:verbose]
234
245
  @project = Project.new( @project ) unless @project.nil?
235
246
  end
247
+
248
+ # takes a series of symbols or an array of symbols
249
+ # for each symbol, creates an instance var from @options[:symbol]
250
+ def variablize_options( *symbols )
251
+ symbols.flatten! # in case someone passes an array
252
+ for sym in symbols
253
+ self.instance_variable_set( :"@#{sym}", @options[sym] )
254
+ end
255
+ end
236
256
  end
237
257
  end
238
258
  end
@@ -0,0 +1,109 @@
1
+ module EpubForge
2
+ module Action
3
+ class Action2
4
+ get_and_set( :project, :args )
5
+ get_and_set_boolean( :verbose )
6
+
7
+ include FunWith::Patterns::Loader
8
+ loader_pattern_configure( :bracketwise_lookup,
9
+ :warn_on_key_change,
10
+ { :verbose => true } )
11
+
12
+
13
+
14
+ include Chatterbox
15
+
16
+ def self.loader_pattern_load_item( file )
17
+ begin
18
+ file.fwf_filepath.load
19
+ rescue Exception => e
20
+ puts "Error loading #{file}: #{e.message}"
21
+ for line in e.backtrace
22
+ puts "\t#{line}"
23
+ end
24
+ end
25
+
26
+ nil # returning true will break loader
27
+ end
28
+
29
+ def self.define_action( keyword, &block )
30
+ puts "defining action #{keyword}" if EpubForge.gem_test_mode?
31
+ definition = ActionDefinition.new
32
+ definition.keyword( keyword )
33
+ definition.klass( self )
34
+
35
+ yield definition if block_given?
36
+
37
+ EpubForge::Action::Action2.loader_pattern_register_item( definition )
38
+ end
39
+
40
+ # # Instead, use these instead of destination_root. Thor gets strings instead of
41
+ # # filepaths, like it wants, and I get filepaths instead of strings, like I want.
42
+ # def destination_root_filepath
43
+ # self.destination_root.fwf_filepath
44
+ # end
45
+ #
46
+ # def destination_root_filepath=(root)
47
+ # @destination_root_file
48
+ # self.destination_root = root.to_s
49
+ # end
50
+ attr_accessor :destination_root_filepath
51
+
52
+ def executable_installed?( name )
53
+ name = name.to_sym
54
+
55
+ if @executables.nil?
56
+ @executables = {}
57
+ for exe, path in (EpubForge.config[:exe_paths] || {})
58
+ @executables[exe] = path.fwf_filepath
59
+ end
60
+ end
61
+
62
+ @executables[name] ||= begin
63
+ _which = `which #{name}`.strip
64
+ (_which.length == 0) ? false : _which.fwf_filepath
65
+ end
66
+
67
+ @executables[name]
68
+ end
69
+
70
+ def requirements
71
+ @requirements ||= []
72
+ end
73
+
74
+ def add_requirement( *args, &block )
75
+ @requirements ||= []
76
+ @requirements.push( [args, block] )
77
+ end
78
+
79
+ def requires_executable( ex, fail_msg )
80
+ add_requirement( ex, fail_msg ) do
81
+ executable_installed?( ex, fail_msg )
82
+ end
83
+ end
84
+
85
+ def must_target_a_project( project_dir )
86
+ add_requirement( project_dir ) do
87
+ Project.is_project_dir?( project_dir )
88
+ end
89
+ end
90
+
91
+ def git_installed?
92
+ executable_installed?('git')
93
+ end
94
+
95
+ def ebook_convert_installed?
96
+ executable_installed?('ebook-convert')
97
+ end
98
+
99
+ def project_already_gitted?
100
+ @project.root_dir.join( ".git" ).directory?
101
+ end
102
+
103
+ def quit_with_error( msg, errno = -1 )
104
+ STDERR.write( "\n#{msg}\n")
105
+ exit( errno )
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,62 @@
1
+ module EpubForge
2
+ module Action
3
+ class ActionDefinition
4
+ # attr_accessor :default_args, :keyword, :klass, :proc
5
+
6
+ get_and_set :help, :usage, :default_args, :keyword, :klass, :proc
7
+ get_and_set_boolean :project_required, :verbose
8
+
9
+ alias :loader_pattern_registry_key :keyword
10
+
11
+ def execute( &block )
12
+ proc( block )
13
+ end
14
+
15
+ def run( *args )
16
+ action = klass.new # one of the action classes (New or Git or Epub, etc.)
17
+ puts( "Sending args to Action(#{self.keyword}) : #{ 'NO ARGS' if args.fwf_blank? }".paint(:pink) ) if EpubForge.gem_test_mode?
18
+ for arg, i in args.each_with_index
19
+ puts " #{i}: #{arg.inspect}".paint(:pink) if verbose?
20
+ end
21
+
22
+ if args.first.is_a?(Project)
23
+ action.project( args.first )
24
+ action.args( args[1..-1] )
25
+ else
26
+ action.args( args )
27
+ end
28
+
29
+ action.instance_exec( &@proc )
30
+ end
31
+
32
+
33
+ def default( name, value )
34
+ (@default_args ||= {})[name] = value
35
+ end
36
+
37
+ # def project_required?
38
+ # @project_required = true if @project_required.nil?
39
+ # @project_required
40
+ # end
41
+
42
+ # def verbose?
43
+ # @verbose == true
44
+ # end
45
+
46
+ # Most actions require -- nay, demand! -- a project to act upon.
47
+ # Add the line 'project_not_required' to the class definition
48
+ # to keep it from failing out if it can't find an existing project.
49
+ # Used for things like initializing new projects, printing help,
50
+ # or... my imagination fails me.
51
+ def project_required?
52
+ @project_required = true if @project_required.nil?
53
+ @project_required
54
+ end
55
+
56
+
57
+ def project_not_required
58
+ @project_required = false
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,45 @@
1
+ # module EpubForge
2
+ # module Action
3
+ # class ActionsLookup
4
+ # attr_accessor :actions, :actions_directories, :keywords
5
+ #
6
+ # def initialize
7
+ # clear
8
+ # end
9
+ #
10
+ # def clear
11
+ # @keywords = {}
12
+ # @actions = []
13
+ # @actions_directories = []
14
+ # end
15
+ #
16
+ # def add_actions( *args )
17
+ # Utils::ActionLoader.load_me( *args )
18
+ #
19
+ # new_actions = Utils::ActionLoader.loaded_classes - @actions
20
+ # @actions += new_actions
21
+ # new_directories = Utils::ActionLoader.loaded_directories - @actions_directories
22
+ # @actions_directories += new_directories
23
+ #
24
+ # for action in new_actions
25
+ # for keyword in action.keywords
26
+ # @keywords[keyword] = action
27
+ # end
28
+ # end
29
+ # end
30
+ #
31
+ # # Find all the actions with keywords that start with the given string.
32
+ # # If this results in more than one action being found, the proper
33
+ # # response is to panic and flail arms.
34
+ # def keyword_to_action( keyword )
35
+ # exact_match = @keywords.keys.select{ |k| k == keyword }
36
+ #
37
+ # return [@keywords[exact_match.first]] if exact_match.length == 1
38
+ #
39
+ # # if no exact match can be found, find a partial match, at the beginning
40
+ # # of the keywords.
41
+ # @keywords.keys.select{ |k| k.match(/^#{keyword}/) }.map{ |k| @keywords[k] }.uniq
42
+ # end
43
+ # end
44
+ # end
45
+ # end
@@ -0,0 +1,93 @@
1
+ module EpubForge
2
+ module Action
3
+ module Chatterbox
4
+ def say( message, color = nil )
5
+ puts message.paint(color)
6
+ end
7
+
8
+ def ask( question, opts = {} )
9
+ while true
10
+ opts[:colors] ||= opts[:color]
11
+
12
+ answer = nil
13
+ input = Readline.readline( question.paint(opts[:colors] ) + " " ).strip
14
+ input.strip
15
+
16
+ if input.fwf_blank?
17
+ if opts[:default]
18
+ answer = opts[:default]
19
+ elsif opts[:blank_allowed] || (opts[:possible_answers] || []).include?("")
20
+ answer = input
21
+ end
22
+ elsif opts[:possible_answers]
23
+ answer = input if opts[:possible_answers].include?( input )
24
+ else
25
+ answer = input
26
+ end
27
+
28
+ if answer.nil?
29
+ say( "'#{input}' is not a valid answer.", :red )
30
+ say( "Possible answers: #{ opts[:possible_answers].inspect }") if opts[:possible_answers]
31
+ end
32
+
33
+ return answer unless answer.nil?
34
+ end
35
+ end
36
+
37
+ def yes?( message, opts = {} )
38
+ opts[:colors] ||= :blue
39
+ opts[:possible_answers] = ["Y", "y", "N", "n", "yes", "no"]
40
+ opts[:default] ||= "y"
41
+
42
+ answer = ask( "#{message} (Y/n)", opts ).downcase[0..1]
43
+
44
+ answer == "y"
45
+ end
46
+
47
+ def yes_prettily?( statement )
48
+ yes?( statement, :color => :pink )
49
+ end
50
+
51
+
52
+ def no?( message, color = nil )
53
+ opts[:allowed] = ["Y", "y", "N", "n"]
54
+ opts[:default] = "n"
55
+ answer = ask( "#{message} (y/N)", opts ).downcase
56
+
57
+ answer == "n"
58
+ end
59
+
60
+ def say_instruction( instruction )
61
+ puts instruction.paint(:yellow)
62
+ end
63
+
64
+
65
+ def ask_from_menu( statement, choices )
66
+ choices.map! do |choice|
67
+ choice.is_a?(String) ? [choice] : choice # I'm being too clever by half here. .first/.last still works.
68
+ end
69
+
70
+ choice_text = ""
71
+ choices.each_with_index do |choice,i|
72
+ choice_text << "\t\t#{i}) #{choice.first}\n"
73
+ end
74
+
75
+ selection = ask( "#{statement}\n\tChoices:\n#{choice_text}>>> ".paint(:blue) )
76
+ choices[selection.to_i].last
77
+ end
78
+
79
+ def ask_prettily( question, *args )
80
+ ask( question.paint(:blue), *args )
81
+ end
82
+
83
+ def say_all_is_well( statement )
84
+ say( statement, :green )
85
+ end
86
+
87
+ def say_error( statement )
88
+ say( statement.paint(:bg_red, :bold) )
89
+ end
90
+
91
+ end
92
+ end
93
+ end