colorcode_convert_rgb 0.1.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.
Files changed (158) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +7 -0
  3. data/Gemfile.lock +23 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +40 -0
  6. data/Rakefile +10 -0
  7. data/bin/console +14 -0
  8. data/bin/setup +8 -0
  9. data/colorcode_convert_rgb.gemspec +30 -0
  10. data/exe/colorcode_convert_rgb +4 -0
  11. data/lib/colorcode_convert_rgb.rb +7 -0
  12. data/lib/colorcode_convert_rgb/cli.rb +13 -0
  13. data/lib/colorcode_convert_rgb/version.rb +3 -0
  14. data/vendor/bundle/ruby/2.5.0/bin/colorcode_convert_rgb +27 -0
  15. data/vendor/bundle/ruby/2.5.0/bin/rake +27 -0
  16. data/vendor/bundle/ruby/2.5.0/bin/thor +27 -0
  17. data/vendor/bundle/ruby/2.5.0/cache/minitest-5.14.2.gem +0 -0
  18. data/vendor/bundle/ruby/2.5.0/cache/rake-12.3.3.gem +0 -0
  19. data/vendor/bundle/ruby/2.5.0/cache/thor-1.0.1.gem +0 -0
  20. data/vendor/bundle/ruby/2.5.0/gems/minitest-5.14.2/.autotest +34 -0
  21. data/vendor/bundle/ruby/2.5.0/gems/minitest-5.14.2/History.rdoc +1397 -0
  22. data/vendor/bundle/ruby/2.5.0/gems/minitest-5.14.2/Manifest.txt +27 -0
  23. data/vendor/bundle/ruby/2.5.0/gems/minitest-5.14.2/README.rdoc +764 -0
  24. data/vendor/bundle/ruby/2.5.0/gems/minitest-5.14.2/Rakefile +74 -0
  25. data/vendor/bundle/ruby/2.5.0/gems/minitest-5.14.2/design_rationale.rb +52 -0
  26. data/vendor/bundle/ruby/2.5.0/gems/minitest-5.14.2/lib/hoe/minitest.rb +32 -0
  27. data/vendor/bundle/ruby/2.5.0/gems/minitest-5.14.2/lib/minitest.rb +1056 -0
  28. data/vendor/bundle/ruby/2.5.0/gems/minitest-5.14.2/lib/minitest/assertions.rb +807 -0
  29. data/vendor/bundle/ruby/2.5.0/gems/minitest-5.14.2/lib/minitest/autorun.rb +13 -0
  30. data/vendor/bundle/ruby/2.5.0/gems/minitest-5.14.2/lib/minitest/benchmark.rb +455 -0
  31. data/vendor/bundle/ruby/2.5.0/gems/minitest-5.14.2/lib/minitest/expectations.rb +303 -0
  32. data/vendor/bundle/ruby/2.5.0/gems/minitest-5.14.2/lib/minitest/hell.rb +11 -0
  33. data/vendor/bundle/ruby/2.5.0/gems/minitest-5.14.2/lib/minitest/mock.rb +240 -0
  34. data/vendor/bundle/ruby/2.5.0/gems/minitest-5.14.2/lib/minitest/parallel.rb +70 -0
  35. data/vendor/bundle/ruby/2.5.0/gems/minitest-5.14.2/lib/minitest/pride.rb +4 -0
  36. data/vendor/bundle/ruby/2.5.0/gems/minitest-5.14.2/lib/minitest/pride_plugin.rb +142 -0
  37. data/vendor/bundle/ruby/2.5.0/gems/minitest-5.14.2/lib/minitest/spec.rb +342 -0
  38. data/vendor/bundle/ruby/2.5.0/gems/minitest-5.14.2/lib/minitest/test.rb +220 -0
  39. data/vendor/bundle/ruby/2.5.0/gems/minitest-5.14.2/lib/minitest/unit.rb +45 -0
  40. data/vendor/bundle/ruby/2.5.0/gems/minitest-5.14.2/test/minitest/metametameta.rb +136 -0
  41. data/vendor/bundle/ruby/2.5.0/gems/minitest-5.14.2/test/minitest/test_minitest_assertions.rb +1575 -0
  42. data/vendor/bundle/ruby/2.5.0/gems/minitest-5.14.2/test/minitest/test_minitest_benchmark.rb +137 -0
  43. data/vendor/bundle/ruby/2.5.0/gems/minitest-5.14.2/test/minitest/test_minitest_mock.rb +872 -0
  44. data/vendor/bundle/ruby/2.5.0/gems/minitest-5.14.2/test/minitest/test_minitest_reporter.rb +299 -0
  45. data/vendor/bundle/ruby/2.5.0/gems/minitest-5.14.2/test/minitest/test_minitest_spec.rb +1061 -0
  46. data/vendor/bundle/ruby/2.5.0/gems/minitest-5.14.2/test/minitest/test_minitest_test.rb +1084 -0
  47. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/CONTRIBUTING.rdoc +43 -0
  48. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/Gemfile +3 -0
  49. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/History.rdoc +2344 -0
  50. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/MIT-LICENSE +21 -0
  51. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/README.rdoc +156 -0
  52. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/Rakefile +41 -0
  53. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/azure-pipelines.yml +11 -0
  54. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/bin/bundle +105 -0
  55. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/bin/console +7 -0
  56. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/bin/rake +29 -0
  57. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/bin/rdoc +29 -0
  58. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/bin/rubocop +29 -0
  59. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/bin/setup +6 -0
  60. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/doc/command_line_usage.rdoc +158 -0
  61. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/doc/example/Rakefile1 +38 -0
  62. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/doc/example/Rakefile2 +35 -0
  63. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/doc/example/a.c +6 -0
  64. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/doc/example/b.c +6 -0
  65. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/doc/example/main.c +11 -0
  66. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/doc/glossary.rdoc +42 -0
  67. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/doc/jamis.rb +592 -0
  68. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/doc/proto_rake.rdoc +127 -0
  69. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/doc/rake.1 +156 -0
  70. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/doc/rakefile.rdoc +622 -0
  71. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/doc/rational.rdoc +151 -0
  72. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/exe/rake +27 -0
  73. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake.rb +71 -0
  74. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/application.rb +824 -0
  75. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/backtrace.rb +24 -0
  76. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/clean.rb +78 -0
  77. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/cloneable.rb +17 -0
  78. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/cpu_counter.rb +107 -0
  79. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/default_loader.rb +15 -0
  80. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/dsl_definition.rb +195 -0
  81. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/early_time.rb +22 -0
  82. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/ext/core.rb +26 -0
  83. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/ext/string.rb +176 -0
  84. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/file_creation_task.rb +25 -0
  85. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/file_list.rb +435 -0
  86. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/file_task.rb +54 -0
  87. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/file_utils.rb +137 -0
  88. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/file_utils_ext.rb +145 -0
  89. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/invocation_chain.rb +57 -0
  90. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/invocation_exception_mixin.rb +17 -0
  91. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/late_time.rb +18 -0
  92. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/linked_list.rb +112 -0
  93. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/loaders/makefile.rb +54 -0
  94. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/multi_task.rb +14 -0
  95. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/name_space.rb +38 -0
  96. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/packagetask.rb +207 -0
  97. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/phony.rb +16 -0
  98. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/private_reader.rb +21 -0
  99. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/promise.rb +100 -0
  100. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/pseudo_status.rb +30 -0
  101. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/rake_module.rb +67 -0
  102. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/rake_test_loader.rb +27 -0
  103. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/rule_recursion_overflow_error.rb +20 -0
  104. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/scope.rb +43 -0
  105. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/task.rb +413 -0
  106. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/task_argument_error.rb +8 -0
  107. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/task_arguments.rb +109 -0
  108. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/task_manager.rb +324 -0
  109. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/tasklib.rb +12 -0
  110. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/testtask.rb +224 -0
  111. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/thread_history_display.rb +49 -0
  112. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/thread_pool.rb +163 -0
  113. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/trace_output.rb +23 -0
  114. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/version.rb +10 -0
  115. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/lib/rake/win32.rb +51 -0
  116. data/vendor/bundle/ruby/2.5.0/gems/rake-12.3.3/rake.gemspec +42 -0
  117. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/.document +5 -0
  118. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/CHANGELOG.md +220 -0
  119. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/CONTRIBUTING.md +15 -0
  120. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/LICENSE.md +20 -0
  121. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/README.md +51 -0
  122. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/bin/thor +6 -0
  123. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/lib/thor.rb +517 -0
  124. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/lib/thor/actions.rb +336 -0
  125. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/lib/thor/actions/create_file.rb +104 -0
  126. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/lib/thor/actions/create_link.rb +61 -0
  127. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/lib/thor/actions/directory.rb +108 -0
  128. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/lib/thor/actions/empty_directory.rb +143 -0
  129. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/lib/thor/actions/file_manipulation.rb +373 -0
  130. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/lib/thor/actions/inject_into_file.rb +120 -0
  131. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/lib/thor/base.rb +699 -0
  132. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/lib/thor/command.rb +142 -0
  133. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/lib/thor/core_ext/hash_with_indifferent_access.rb +97 -0
  134. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/lib/thor/error.rb +110 -0
  135. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/lib/thor/group.rb +281 -0
  136. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/lib/thor/invocation.rb +178 -0
  137. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/lib/thor/line_editor.rb +17 -0
  138. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/lib/thor/line_editor/basic.rb +37 -0
  139. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/lib/thor/line_editor/readline.rb +88 -0
  140. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/lib/thor/nested_context.rb +29 -0
  141. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/lib/thor/parser.rb +4 -0
  142. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/lib/thor/parser/argument.rb +70 -0
  143. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/lib/thor/parser/arguments.rb +175 -0
  144. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/lib/thor/parser/option.rb +159 -0
  145. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/lib/thor/parser/options.rb +236 -0
  146. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/lib/thor/rake_compat.rb +72 -0
  147. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/lib/thor/runner.rb +325 -0
  148. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/lib/thor/shell.rb +81 -0
  149. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/lib/thor/shell/basic.rb +491 -0
  150. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/lib/thor/shell/color.rb +153 -0
  151. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/lib/thor/shell/html.rb +126 -0
  152. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/lib/thor/util.rb +284 -0
  153. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/lib/thor/version.rb +3 -0
  154. data/vendor/bundle/ruby/2.5.0/gems/thor-1.0.1/thor.gemspec +28 -0
  155. data/vendor/bundle/ruby/2.5.0/specifications/minitest-5.14.2.gemspec +38 -0
  156. data/vendor/bundle/ruby/2.5.0/specifications/rake-12.3.3.gemspec +43 -0
  157. data/vendor/bundle/ruby/2.5.0/specifications/thor-1.0.1.gemspec +34 -0
  158. metadata +214 -0
@@ -0,0 +1,325 @@
1
+ require_relative "../thor"
2
+ require_relative "group"
3
+
4
+ require "yaml"
5
+ require "digest/md5"
6
+ require "pathname"
7
+
8
+ class Thor::Runner < Thor #:nodoc: # rubocop:disable ClassLength
9
+ autoload :OpenURI, "open-uri"
10
+
11
+ map "-T" => :list, "-i" => :install, "-u" => :update, "-v" => :version
12
+
13
+ def self.banner(command, all = false, subcommand = false)
14
+ "thor " + command.formatted_usage(self, all, subcommand)
15
+ end
16
+
17
+ def self.exit_on_failure?
18
+ true
19
+ end
20
+
21
+ # Override Thor#help so it can give information about any class and any method.
22
+ #
23
+ def help(meth = nil)
24
+ if meth && !respond_to?(meth)
25
+ initialize_thorfiles(meth)
26
+ klass, command = Thor::Util.find_class_and_command_by_namespace(meth)
27
+ self.class.handle_no_command_error(command, false) if klass.nil?
28
+ klass.start(["-h", command].compact, :shell => shell)
29
+ else
30
+ super
31
+ end
32
+ end
33
+
34
+ # If a command is not found on Thor::Runner, method missing is invoked and
35
+ # Thor::Runner is then responsible for finding the command in all classes.
36
+ #
37
+ def method_missing(meth, *args)
38
+ meth = meth.to_s
39
+ initialize_thorfiles(meth)
40
+ klass, command = Thor::Util.find_class_and_command_by_namespace(meth)
41
+ self.class.handle_no_command_error(command, false) if klass.nil?
42
+ args.unshift(command) if command
43
+ klass.start(args, :shell => shell)
44
+ end
45
+
46
+ desc "install NAME", "Install an optionally named Thor file into your system commands"
47
+ method_options :as => :string, :relative => :boolean, :force => :boolean
48
+ def install(name) # rubocop:disable MethodLength
49
+ initialize_thorfiles
50
+
51
+ # If a directory name is provided as the argument, look for a 'main.thor'
52
+ # command in said directory.
53
+ begin
54
+ if File.directory?(File.expand_path(name))
55
+ base = File.join(name, "main.thor")
56
+ package = :directory
57
+ contents = open(base, &:read)
58
+ else
59
+ base = name
60
+ package = :file
61
+ contents = open(name, &:read)
62
+ end
63
+ rescue OpenURI::HTTPError
64
+ raise Error, "Error opening URI '#{name}'"
65
+ rescue Errno::ENOENT
66
+ raise Error, "Error opening file '#{name}'"
67
+ end
68
+
69
+ say "Your Thorfile contains:"
70
+ say contents
71
+
72
+ unless options["force"]
73
+ return false if no?("Do you wish to continue [y/N]?")
74
+ end
75
+
76
+ as = options["as"] || begin
77
+ first_line = contents.split("\n")[0]
78
+ (match = first_line.match(/\s*#\s*module:\s*([^\n]*)/)) ? match[1].strip : nil
79
+ end
80
+
81
+ unless as
82
+ basename = File.basename(name)
83
+ as = ask("Please specify a name for #{name} in the system repository [#{basename}]:")
84
+ as = basename if as.empty?
85
+ end
86
+
87
+ location = if options[:relative] || name =~ %r{^https?://}
88
+ name
89
+ else
90
+ File.expand_path(name)
91
+ end
92
+
93
+ thor_yaml[as] = {
94
+ :filename => Digest::MD5.hexdigest(name + as),
95
+ :location => location,
96
+ :namespaces => Thor::Util.namespaces_in_content(contents, base)
97
+ }
98
+
99
+ save_yaml(thor_yaml)
100
+ say "Storing thor file in your system repository"
101
+ destination = File.join(thor_root, thor_yaml[as][:filename])
102
+
103
+ if package == :file
104
+ File.open(destination, "w") { |f| f.puts contents }
105
+ else
106
+ require "fileutils"
107
+ FileUtils.cp_r(name, destination)
108
+ end
109
+
110
+ thor_yaml[as][:filename] # Indicate success
111
+ end
112
+
113
+ desc "version", "Show Thor version"
114
+ def version
115
+ require_relative "version"
116
+ say "Thor #{Thor::VERSION}"
117
+ end
118
+
119
+ desc "uninstall NAME", "Uninstall a named Thor module"
120
+ def uninstall(name)
121
+ raise Error, "Can't find module '#{name}'" unless thor_yaml[name]
122
+ say "Uninstalling #{name}."
123
+ require "fileutils"
124
+ FileUtils.rm_rf(File.join(thor_root, (thor_yaml[name][:filename]).to_s))
125
+
126
+ thor_yaml.delete(name)
127
+ save_yaml(thor_yaml)
128
+
129
+ puts "Done."
130
+ end
131
+
132
+ desc "update NAME", "Update a Thor file from its original location"
133
+ def update(name)
134
+ raise Error, "Can't find module '#{name}'" if !thor_yaml[name] || !thor_yaml[name][:location]
135
+
136
+ say "Updating '#{name}' from #{thor_yaml[name][:location]}"
137
+
138
+ old_filename = thor_yaml[name][:filename]
139
+ self.options = options.merge("as" => name)
140
+
141
+ if File.directory? File.expand_path(name)
142
+ require "fileutils"
143
+ FileUtils.rm_rf(File.join(thor_root, old_filename))
144
+
145
+ thor_yaml.delete(old_filename)
146
+ save_yaml(thor_yaml)
147
+
148
+ filename = install(name)
149
+ else
150
+ filename = install(thor_yaml[name][:location])
151
+ end
152
+
153
+ File.delete(File.join(thor_root, old_filename)) unless filename == old_filename
154
+ end
155
+
156
+ desc "installed", "List the installed Thor modules and commands"
157
+ method_options :internal => :boolean
158
+ def installed
159
+ initialize_thorfiles(nil, true)
160
+ display_klasses(true, options["internal"])
161
+ end
162
+
163
+ desc "list [SEARCH]", "List the available thor commands (--substring means .*SEARCH)"
164
+ method_options :substring => :boolean, :group => :string, :all => :boolean, :debug => :boolean
165
+ def list(search = "")
166
+ initialize_thorfiles
167
+
168
+ search = ".*#{search}" if options["substring"]
169
+ search = /^#{search}.*/i
170
+ group = options[:group] || "standard"
171
+
172
+ klasses = Thor::Base.subclasses.select do |k|
173
+ (options[:all] || k.group == group) && k.namespace =~ search
174
+ end
175
+
176
+ display_klasses(false, false, klasses)
177
+ end
178
+
179
+ private
180
+
181
+ def thor_root
182
+ Thor::Util.thor_root
183
+ end
184
+
185
+ def thor_yaml
186
+ @thor_yaml ||= begin
187
+ yaml_file = File.join(thor_root, "thor.yml")
188
+ yaml = YAML.load_file(yaml_file) if File.exist?(yaml_file)
189
+ yaml || {}
190
+ end
191
+ end
192
+
193
+ # Save the yaml file. If none exists in thor root, creates one.
194
+ #
195
+ def save_yaml(yaml)
196
+ yaml_file = File.join(thor_root, "thor.yml")
197
+
198
+ unless File.exist?(yaml_file)
199
+ require "fileutils"
200
+ FileUtils.mkdir_p(thor_root)
201
+ yaml_file = File.join(thor_root, "thor.yml")
202
+ FileUtils.touch(yaml_file)
203
+ end
204
+
205
+ File.open(yaml_file, "w") { |f| f.puts yaml.to_yaml }
206
+ end
207
+
208
+ # Load the Thorfiles. If relevant_to is supplied, looks for specific files
209
+ # in the thor_root instead of loading them all.
210
+ #
211
+ # By default, it also traverses the current path until find Thor files, as
212
+ # described in thorfiles. This look up can be skipped by supplying
213
+ # skip_lookup true.
214
+ #
215
+ def initialize_thorfiles(relevant_to = nil, skip_lookup = false)
216
+ thorfiles(relevant_to, skip_lookup).each do |f|
217
+ Thor::Util.load_thorfile(f, nil, options[:debug]) unless Thor::Base.subclass_files.keys.include?(File.expand_path(f))
218
+ end
219
+ end
220
+
221
+ # Finds Thorfiles by traversing from your current directory down to the root
222
+ # directory of your system. If at any time we find a Thor file, we stop.
223
+ #
224
+ # We also ensure that system-wide Thorfiles are loaded first, so local
225
+ # Thorfiles can override them.
226
+ #
227
+ # ==== Example
228
+ #
229
+ # If we start at /Users/wycats/dev/thor ...
230
+ #
231
+ # 1. /Users/wycats/dev/thor
232
+ # 2. /Users/wycats/dev
233
+ # 3. /Users/wycats <-- we find a Thorfile here, so we stop
234
+ #
235
+ # Suppose we start at c:\Documents and Settings\james\dev\thor ...
236
+ #
237
+ # 1. c:\Documents and Settings\james\dev\thor
238
+ # 2. c:\Documents and Settings\james\dev
239
+ # 3. c:\Documents and Settings\james
240
+ # 4. c:\Documents and Settings
241
+ # 5. c:\ <-- no Thorfiles found!
242
+ #
243
+ def thorfiles(relevant_to = nil, skip_lookup = false)
244
+ thorfiles = []
245
+
246
+ unless skip_lookup
247
+ Pathname.pwd.ascend do |path|
248
+ thorfiles = Thor::Util.globs_for(path).map { |g| Dir[g] }.flatten
249
+ break unless thorfiles.empty?
250
+ end
251
+ end
252
+
253
+ files = (relevant_to ? thorfiles_relevant_to(relevant_to) : Thor::Util.thor_root_glob)
254
+ files += thorfiles
255
+ files -= ["#{thor_root}/thor.yml"]
256
+
257
+ files.map! do |file|
258
+ File.directory?(file) ? File.join(file, "main.thor") : file
259
+ end
260
+ end
261
+
262
+ # Load Thorfiles relevant to the given method. If you provide "foo:bar" it
263
+ # will load all thor files in the thor.yaml that has "foo" e "foo:bar"
264
+ # namespaces registered.
265
+ #
266
+ def thorfiles_relevant_to(meth)
267
+ lookup = [meth, meth.split(":")[0...-1].join(":")]
268
+
269
+ files = thor_yaml.select do |_, v|
270
+ v[:namespaces] && !(v[:namespaces] & lookup).empty?
271
+ end
272
+
273
+ files.map { |_, v| File.join(thor_root, (v[:filename]).to_s) }
274
+ end
275
+
276
+ # Display information about the given klasses. If with_module is given,
277
+ # it shows a table with information extracted from the yaml file.
278
+ #
279
+ def display_klasses(with_modules = false, show_internal = false, klasses = Thor::Base.subclasses)
280
+ klasses -= [Thor, Thor::Runner, Thor::Group] unless show_internal
281
+
282
+ raise Error, "No Thor commands available" if klasses.empty?
283
+ show_modules if with_modules && !thor_yaml.empty?
284
+
285
+ list = Hash.new { |h, k| h[k] = [] }
286
+ groups = klasses.select { |k| k.ancestors.include?(Thor::Group) }
287
+
288
+ # Get classes which inherit from Thor
289
+ (klasses - groups).each { |k| list[k.namespace.split(":").first] += k.printable_commands(false) }
290
+
291
+ # Get classes which inherit from Thor::Base
292
+ groups.map! { |k| k.printable_commands(false).first }
293
+ list["root"] = groups
294
+
295
+ # Order namespaces with default coming first
296
+ list = list.sort { |a, b| a[0].sub(/^default/, "") <=> b[0].sub(/^default/, "") }
297
+ list.each { |n, commands| display_commands(n, commands) unless commands.empty? }
298
+ end
299
+
300
+ def display_commands(namespace, list) #:nodoc:
301
+ list.sort! { |a, b| a[0] <=> b[0] }
302
+
303
+ say shell.set_color(namespace, :blue, true)
304
+ say "-" * namespace.size
305
+
306
+ print_table(list, :truncate => true)
307
+ say
308
+ end
309
+ alias_method :display_tasks, :display_commands
310
+
311
+ def show_modules #:nodoc:
312
+ info = []
313
+ labels = %w(Modules Namespaces)
314
+
315
+ info << labels
316
+ info << ["-" * labels[0].size, "-" * labels[1].size]
317
+
318
+ thor_yaml.each do |name, hash|
319
+ info << [name, hash[:namespaces].join(", ")]
320
+ end
321
+
322
+ print_table info
323
+ say ""
324
+ end
325
+ end
@@ -0,0 +1,81 @@
1
+ require "rbconfig"
2
+
3
+ class Thor
4
+ module Base
5
+ class << self
6
+ attr_writer :shell
7
+
8
+ # Returns the shell used in all Thor classes. If you are in a Unix platform
9
+ # it will use a colored log, otherwise it will use a basic one without color.
10
+ #
11
+ def shell
12
+ @shell ||= if ENV["THOR_SHELL"] && !ENV["THOR_SHELL"].empty?
13
+ Thor::Shell.const_get(ENV["THOR_SHELL"])
14
+ elsif RbConfig::CONFIG["host_os"] =~ /mswin|mingw/ && !ENV["ANSICON"]
15
+ Thor::Shell::Basic
16
+ else
17
+ Thor::Shell::Color
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ module Shell
24
+ SHELL_DELEGATED_METHODS = [:ask, :error, :set_color, :yes?, :no?, :say, :say_status, :print_in_columns, :print_table, :print_wrapped, :file_collision, :terminal_width]
25
+ attr_writer :shell
26
+
27
+ autoload :Basic, File.expand_path("shell/basic", __dir__)
28
+ autoload :Color, File.expand_path("shell/color", __dir__)
29
+ autoload :HTML, File.expand_path("shell/html", __dir__)
30
+
31
+ # Add shell to initialize config values.
32
+ #
33
+ # ==== Configuration
34
+ # shell<Object>:: An instance of the shell to be used.
35
+ #
36
+ # ==== Examples
37
+ #
38
+ # class MyScript < Thor
39
+ # argument :first, :type => :numeric
40
+ # end
41
+ #
42
+ # MyScript.new [1.0], { :foo => :bar }, :shell => Thor::Shell::Basic.new
43
+ #
44
+ def initialize(args = [], options = {}, config = {})
45
+ super
46
+ self.shell = config[:shell]
47
+ shell.base ||= self if shell.respond_to?(:base)
48
+ end
49
+
50
+ # Holds the shell for the given Thor instance. If no shell is given,
51
+ # it gets a default shell from Thor::Base.shell.
52
+ def shell
53
+ @shell ||= Thor::Base.shell.new
54
+ end
55
+
56
+ # Common methods that are delegated to the shell.
57
+ SHELL_DELEGATED_METHODS.each do |method|
58
+ module_eval <<-METHOD, __FILE__, __LINE__ + 1
59
+ def #{method}(*args,&block)
60
+ shell.#{method}(*args,&block)
61
+ end
62
+ METHOD
63
+ end
64
+
65
+ # Yields the given block with padding.
66
+ def with_padding
67
+ shell.padding += 1
68
+ yield
69
+ ensure
70
+ shell.padding -= 1
71
+ end
72
+
73
+ protected
74
+
75
+ # Allow shell to be shared between invocations.
76
+ #
77
+ def _shared_configuration #:nodoc:
78
+ super.merge!(:shell => shell)
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,491 @@
1
+ class Thor
2
+ module Shell
3
+ class Basic
4
+ DEFAULT_TERMINAL_WIDTH = 80
5
+
6
+ attr_accessor :base
7
+ attr_reader :padding
8
+
9
+ # Initialize base, mute and padding to nil.
10
+ #
11
+ def initialize #:nodoc:
12
+ @base = nil
13
+ @mute = false
14
+ @padding = 0
15
+ @always_force = false
16
+ end
17
+
18
+ # Mute everything that's inside given block
19
+ #
20
+ def mute
21
+ @mute = true
22
+ yield
23
+ ensure
24
+ @mute = false
25
+ end
26
+
27
+ # Check if base is muted
28
+ #
29
+ def mute?
30
+ @mute
31
+ end
32
+
33
+ # Sets the output padding, not allowing less than zero values.
34
+ #
35
+ def padding=(value)
36
+ @padding = [0, value].max
37
+ end
38
+
39
+ # Sets the output padding while executing a block and resets it.
40
+ #
41
+ def indent(count = 1)
42
+ orig_padding = padding
43
+ self.padding = padding + count
44
+ yield
45
+ self.padding = orig_padding
46
+ end
47
+
48
+ # Asks something to the user and receives a response.
49
+ #
50
+ # If a default value is specified it will be presented to the user
51
+ # and allows them to select that value with an empty response. This
52
+ # option is ignored when limited answers are supplied.
53
+ #
54
+ # If asked to limit the correct responses, you can pass in an
55
+ # array of acceptable answers. If one of those is not supplied,
56
+ # they will be shown a message stating that one of those answers
57
+ # must be given and re-asked the question.
58
+ #
59
+ # If asking for sensitive information, the :echo option can be set
60
+ # to false to mask user input from $stdin.
61
+ #
62
+ # If the required input is a path, then set the path option to
63
+ # true. This will enable tab completion for file paths relative
64
+ # to the current working directory on systems that support
65
+ # Readline.
66
+ #
67
+ # ==== Example
68
+ # ask("What is your name?")
69
+ #
70
+ # ask("What is the planet furthest from the sun?", :default => "Pluto")
71
+ #
72
+ # ask("What is your favorite Neopolitan flavor?", :limited_to => ["strawberry", "chocolate", "vanilla"])
73
+ #
74
+ # ask("What is your password?", :echo => false)
75
+ #
76
+ # ask("Where should the file be saved?", :path => true)
77
+ #
78
+ def ask(statement, *args)
79
+ options = args.last.is_a?(Hash) ? args.pop : {}
80
+ color = args.first
81
+
82
+ if options[:limited_to]
83
+ ask_filtered(statement, color, options)
84
+ else
85
+ ask_simply(statement, color, options)
86
+ end
87
+ end
88
+
89
+ # Say (print) something to the user. If the sentence ends with a whitespace
90
+ # or tab character, a new line is not appended (print + flush). Otherwise
91
+ # are passed straight to puts (behavior got from Highline).
92
+ #
93
+ # ==== Example
94
+ # say("I know you knew that.")
95
+ #
96
+ def say(message = "", color = nil, force_new_line = (message.to_s !~ /( |\t)\Z/))
97
+ buffer = prepare_message(message, *color)
98
+ buffer << "\n" if force_new_line && !message.to_s.end_with?("\n")
99
+
100
+ stdout.print(buffer)
101
+ stdout.flush
102
+ end
103
+
104
+ # Say a status with the given color and appends the message. Since this
105
+ # method is used frequently by actions, it allows nil or false to be given
106
+ # in log_status, avoiding the message from being shown. If a Symbol is
107
+ # given in log_status, it's used as the color.
108
+ #
109
+ def say_status(status, message, log_status = true)
110
+ return if quiet? || log_status == false
111
+ spaces = " " * (padding + 1)
112
+ color = log_status.is_a?(Symbol) ? log_status : :green
113
+
114
+ status = status.to_s.rjust(12)
115
+ status = set_color status, color, true if color
116
+
117
+ buffer = "#{status}#{spaces}#{message}"
118
+ buffer = "#{buffer}\n" unless buffer.end_with?("\n")
119
+
120
+ stdout.print(buffer)
121
+ stdout.flush
122
+ end
123
+
124
+ # Make a question the to user and returns true if the user replies "y" or
125
+ # "yes".
126
+ #
127
+ def yes?(statement, color = nil)
128
+ !!(ask(statement, color, :add_to_history => false) =~ is?(:yes))
129
+ end
130
+
131
+ # Make a question the to user and returns true if the user replies "n" or
132
+ # "no".
133
+ #
134
+ def no?(statement, color = nil)
135
+ !!(ask(statement, color, :add_to_history => false) =~ is?(:no))
136
+ end
137
+
138
+ # Prints values in columns
139
+ #
140
+ # ==== Parameters
141
+ # Array[String, String, ...]
142
+ #
143
+ def print_in_columns(array)
144
+ return if array.empty?
145
+ colwidth = (array.map { |el| el.to_s.size }.max || 0) + 2
146
+ array.each_with_index do |value, index|
147
+ # Don't output trailing spaces when printing the last column
148
+ if ((((index + 1) % (terminal_width / colwidth))).zero? && !index.zero?) || index + 1 == array.length
149
+ stdout.puts value
150
+ else
151
+ stdout.printf("%-#{colwidth}s", value)
152
+ end
153
+ end
154
+ end
155
+
156
+ # Prints a table.
157
+ #
158
+ # ==== Parameters
159
+ # Array[Array[String, String, ...]]
160
+ #
161
+ # ==== Options
162
+ # indent<Integer>:: Indent the first column by indent value.
163
+ # colwidth<Integer>:: Force the first column to colwidth spaces wide.
164
+ #
165
+ def print_table(array, options = {}) # rubocop:disable MethodLength
166
+ return if array.empty?
167
+
168
+ formats = []
169
+ indent = options[:indent].to_i
170
+ colwidth = options[:colwidth]
171
+ options[:truncate] = terminal_width if options[:truncate] == true
172
+
173
+ formats << "%-#{colwidth + 2}s".dup if colwidth
174
+ start = colwidth ? 1 : 0
175
+
176
+ colcount = array.max { |a, b| a.size <=> b.size }.size
177
+
178
+ maximas = []
179
+
180
+ start.upto(colcount - 1) do |index|
181
+ maxima = array.map { |row| row[index] ? row[index].to_s.size : 0 }.max
182
+ maximas << maxima
183
+ formats << if index == colcount - 1
184
+ # Don't output 2 trailing spaces when printing the last column
185
+ "%-s".dup
186
+ else
187
+ "%-#{maxima + 2}s".dup
188
+ end
189
+ end
190
+
191
+ formats[0] = formats[0].insert(0, " " * indent)
192
+ formats << "%s"
193
+
194
+ array.each do |row|
195
+ sentence = "".dup
196
+
197
+ row.each_with_index do |column, index|
198
+ maxima = maximas[index]
199
+
200
+ f = if column.is_a?(Numeric)
201
+ if index == row.size - 1
202
+ # Don't output 2 trailing spaces when printing the last column
203
+ "%#{maxima}s"
204
+ else
205
+ "%#{maxima}s "
206
+ end
207
+ else
208
+ formats[index]
209
+ end
210
+ sentence << f % column.to_s
211
+ end
212
+
213
+ sentence = truncate(sentence, options[:truncate]) if options[:truncate]
214
+ stdout.puts sentence
215
+ end
216
+ end
217
+
218
+ # Prints a long string, word-wrapping the text to the current width of the
219
+ # terminal display. Ideal for printing heredocs.
220
+ #
221
+ # ==== Parameters
222
+ # String
223
+ #
224
+ # ==== Options
225
+ # indent<Integer>:: Indent each line of the printed paragraph by indent value.
226
+ #
227
+ def print_wrapped(message, options = {})
228
+ indent = options[:indent] || 0
229
+ width = terminal_width - indent
230
+ paras = message.split("\n\n")
231
+
232
+ paras.map! do |unwrapped|
233
+ counter = 0
234
+ unwrapped.split(" ").inject do |memo, word|
235
+ word = word.gsub(/\n\005/, "\n").gsub(/\005/, "\n")
236
+ counter = 0 if word.include? "\n"
237
+ if (counter + word.length + 1) < width
238
+ memo = "#{memo} #{word}"
239
+ counter += (word.length + 1)
240
+ else
241
+ memo = "#{memo}\n#{word}"
242
+ counter = word.length
243
+ end
244
+ memo
245
+ end
246
+ end.compact!
247
+
248
+ paras.each do |para|
249
+ para.split("\n").each do |line|
250
+ stdout.puts line.insert(0, " " * indent)
251
+ end
252
+ stdout.puts unless para == paras.last
253
+ end
254
+ end
255
+
256
+ # Deals with file collision and returns true if the file should be
257
+ # overwritten and false otherwise. If a block is given, it uses the block
258
+ # response as the content for the diff.
259
+ #
260
+ # ==== Parameters
261
+ # destination<String>:: the destination file to solve conflicts
262
+ # block<Proc>:: an optional block that returns the value to be used in diff and merge
263
+ #
264
+ def file_collision(destination)
265
+ return true if @always_force
266
+ options = block_given? ? "[Ynaqdhm]" : "[Ynaqh]"
267
+
268
+ loop do
269
+ answer = ask(
270
+ %[Overwrite #{destination}? (enter "h" for help) #{options}],
271
+ :add_to_history => false
272
+ )
273
+
274
+ case answer
275
+ when nil
276
+ say ""
277
+ return true
278
+ when is?(:yes), is?(:force), ""
279
+ return true
280
+ when is?(:no), is?(:skip)
281
+ return false
282
+ when is?(:always)
283
+ return @always_force = true
284
+ when is?(:quit)
285
+ say "Aborting..."
286
+ raise SystemExit
287
+ when is?(:diff)
288
+ show_diff(destination, yield) if block_given?
289
+ say "Retrying..."
290
+ when is?(:merge)
291
+ if block_given? && !merge_tool.empty?
292
+ merge(destination, yield)
293
+ return nil
294
+ end
295
+
296
+ say "Please specify merge tool to `THOR_MERGE` env."
297
+ else
298
+ say file_collision_help
299
+ end
300
+ end
301
+ end
302
+
303
+ # This code was copied from Rake, available under MIT-LICENSE
304
+ # Copyright (c) 2003, 2004 Jim Weirich
305
+ def terminal_width
306
+ result = if ENV["THOR_COLUMNS"]
307
+ ENV["THOR_COLUMNS"].to_i
308
+ else
309
+ unix? ? dynamic_width : DEFAULT_TERMINAL_WIDTH
310
+ end
311
+ result < 10 ? DEFAULT_TERMINAL_WIDTH : result
312
+ rescue
313
+ DEFAULT_TERMINAL_WIDTH
314
+ end
315
+
316
+ # Called if something goes wrong during the execution. This is used by Thor
317
+ # internally and should not be used inside your scripts. If something went
318
+ # wrong, you can always raise an exception. If you raise a Thor::Error, it
319
+ # will be rescued and wrapped in the method below.
320
+ #
321
+ def error(statement)
322
+ stderr.puts statement
323
+ end
324
+
325
+ # Apply color to the given string with optional bold. Disabled in the
326
+ # Thor::Shell::Basic class.
327
+ #
328
+ def set_color(string, *) #:nodoc:
329
+ string
330
+ end
331
+
332
+ protected
333
+
334
+ def prepare_message(message, *color)
335
+ spaces = " " * padding
336
+ spaces + set_color(message.to_s, *color)
337
+ end
338
+
339
+ def can_display_colors?
340
+ false
341
+ end
342
+
343
+ def lookup_color(color)
344
+ return color unless color.is_a?(Symbol)
345
+ self.class.const_get(color.to_s.upcase)
346
+ end
347
+
348
+ def stdout
349
+ $stdout
350
+ end
351
+
352
+ def stderr
353
+ $stderr
354
+ end
355
+
356
+ def is?(value) #:nodoc:
357
+ value = value.to_s
358
+
359
+ if value.size == 1
360
+ /\A#{value}\z/i
361
+ else
362
+ /\A(#{value}|#{value[0, 1]})\z/i
363
+ end
364
+ end
365
+
366
+ def file_collision_help #:nodoc:
367
+ <<-HELP
368
+ Y - yes, overwrite
369
+ n - no, do not overwrite
370
+ a - all, overwrite this and all others
371
+ q - quit, abort
372
+ d - diff, show the differences between the old and the new
373
+ h - help, show this help
374
+ m - merge, run merge tool
375
+ HELP
376
+ end
377
+
378
+ def show_diff(destination, content) #:nodoc:
379
+ diff_cmd = ENV["THOR_DIFF"] || ENV["RAILS_DIFF"] || "diff -u"
380
+
381
+ require "tempfile"
382
+ Tempfile.open(File.basename(destination), File.dirname(destination)) do |temp|
383
+ temp.write content
384
+ temp.rewind
385
+ system %(#{diff_cmd} "#{destination}" "#{temp.path}")
386
+ end
387
+ end
388
+
389
+ def quiet? #:nodoc:
390
+ mute? || (base && base.options[:quiet])
391
+ end
392
+
393
+ # Calculate the dynamic width of the terminal
394
+ def dynamic_width
395
+ @dynamic_width ||= (dynamic_width_stty.nonzero? || dynamic_width_tput)
396
+ end
397
+
398
+ def dynamic_width_stty
399
+ `stty size 2>/dev/null`.split[1].to_i
400
+ end
401
+
402
+ def dynamic_width_tput
403
+ `tput cols 2>/dev/null`.to_i
404
+ end
405
+
406
+ def unix?
407
+ RUBY_PLATFORM =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris|irix|hpux)/i
408
+ end
409
+
410
+ def truncate(string, width)
411
+ as_unicode do
412
+ chars = string.chars.to_a
413
+ if chars.length <= width
414
+ chars.join
415
+ else
416
+ chars[0, width - 3].join + "..."
417
+ end
418
+ end
419
+ end
420
+
421
+ if "".respond_to?(:encode)
422
+ def as_unicode
423
+ yield
424
+ end
425
+ else
426
+ def as_unicode
427
+ old = $KCODE
428
+ $KCODE = "U"
429
+ yield
430
+ ensure
431
+ $KCODE = old
432
+ end
433
+ end
434
+
435
+ def ask_simply(statement, color, options)
436
+ default = options[:default]
437
+ message = [statement, ("(#{default})" if default), nil].uniq.join(" ")
438
+ message = prepare_message(message, *color)
439
+ result = Thor::LineEditor.readline(message, options)
440
+
441
+ return unless result
442
+
443
+ result = result.strip
444
+
445
+ if default && result == ""
446
+ default
447
+ else
448
+ result
449
+ end
450
+ end
451
+
452
+ def ask_filtered(statement, color, options)
453
+ answer_set = options[:limited_to]
454
+ case_insensitive = options.fetch(:case_insensitive, false)
455
+ correct_answer = nil
456
+ until correct_answer
457
+ answers = answer_set.join(", ")
458
+ answer = ask_simply("#{statement} [#{answers}]", color, options)
459
+ correct_answer = answer_match(answer_set, answer, case_insensitive)
460
+ say("Your response must be one of: [#{answers}]. Please try again.") unless correct_answer
461
+ end
462
+ correct_answer
463
+ end
464
+
465
+ def answer_match(possibilities, answer, case_insensitive)
466
+ if case_insensitive
467
+ possibilities.detect{ |possibility| possibility.downcase == answer.downcase }
468
+ else
469
+ possibilities.detect{ |possibility| possibility == answer }
470
+ end
471
+ end
472
+
473
+ def merge(destination, content) #:nodoc:
474
+ require "tempfile"
475
+ Tempfile.open([File.basename(destination), File.extname(destination)], File.dirname(destination)) do |temp|
476
+ temp.write content
477
+ temp.rewind
478
+ system %(#{merge_tool} "#{temp.path}" "#{destination}")
479
+ end
480
+ end
481
+
482
+ def merge_tool #:nodoc:
483
+ @merge_tool ||= ENV["THOR_MERGE"] || git_merge_tool
484
+ end
485
+
486
+ def git_merge_tool #:nodoc:
487
+ `git config merge.tool`.rstrip rescue ""
488
+ end
489
+ end
490
+ end
491
+ end