stickyflag 0.2.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 (76) hide show
  1. data/.gitignore +7 -0
  2. data/.rspec +4 -0
  3. data/.simplecov +9 -0
  4. data/.travis.yml +13 -0
  5. data/Gemfile +2 -0
  6. data/LICENSE.md +7 -0
  7. data/README.md +49 -0
  8. data/Rakefile +19 -0
  9. data/TODO.md +3 -0
  10. data/bin/stickyflag +6 -0
  11. data/features/clear.feature +14 -0
  12. data/features/clear_quietly.feature +23 -0
  13. data/features/configuration.feature +14 -0
  14. data/features/get.feature +14 -0
  15. data/features/get_quietly.feature +23 -0
  16. data/features/set.feature +14 -0
  17. data/features/set_quietly.feature +22 -0
  18. data/features/step_definitions/configuration_steps.rb +31 -0
  19. data/features/step_definitions/database_steps.rb +41 -0
  20. data/features/step_definitions/pending_steps.rb +5 -0
  21. data/features/step_definitions/tag_steps.rb +62 -0
  22. data/features/support/cukegem.rb +82 -0
  23. data/features/support/env.rb +37 -0
  24. data/features/tags.feature +18 -0
  25. data/features/unset.feature +14 -0
  26. data/features/unset_quietly.feature +23 -0
  27. data/lib/stickyflag/configuration.rb +66 -0
  28. data/lib/stickyflag/database.rb +162 -0
  29. data/lib/stickyflag/external_cmds.rb +64 -0
  30. data/lib/stickyflag/patches/tempfile_encoding.rb +22 -0
  31. data/lib/stickyflag/patches/tmpnam.rb +38 -0
  32. data/lib/stickyflag/paths.rb +47 -0
  33. data/lib/stickyflag/tag_factory.rb +108 -0
  34. data/lib/stickyflag/tags/c.rb +25 -0
  35. data/lib/stickyflag/tags/mmd.rb +168 -0
  36. data/lib/stickyflag/tags/pdf.rb +119 -0
  37. data/lib/stickyflag/tags/png.rb +61 -0
  38. data/lib/stickyflag/tags/source_code.rb +99 -0
  39. data/lib/stickyflag/tags/tex.rb +25 -0
  40. data/lib/stickyflag/version.rb +12 -0
  41. data/lib/stickyflag.rb +253 -0
  42. data/spec/spec_helper.rb +22 -0
  43. data/spec/stickyflag/configuration_spec.rb +132 -0
  44. data/spec/stickyflag/database_spec.rb +331 -0
  45. data/spec/stickyflag/external_cmds_spec.rb +175 -0
  46. data/spec/stickyflag/patches/tempfile_encoding_spec.rb +26 -0
  47. data/spec/stickyflag/patches/tmpnam_spec.rb +35 -0
  48. data/spec/stickyflag/paths_spec.rb +29 -0
  49. data/spec/stickyflag/tag_factory_spec.rb +185 -0
  50. data/spec/stickyflag/tags/c_spec.rb +14 -0
  51. data/spec/stickyflag/tags/mmd_spec.rb +40 -0
  52. data/spec/stickyflag/tags/pdf_spec.rb +39 -0
  53. data/spec/stickyflag/tags/png_spec.rb +6 -0
  54. data/spec/stickyflag/tags/tex_spec.rb +6 -0
  55. data/spec/stickyflag_spec.rb +482 -0
  56. data/spec/support/examples/c_all_comments.c +3 -0
  57. data/spec/support/examples/c_no_tags.c +5 -0
  58. data/spec/support/examples/c_with_tag.c +6 -0
  59. data/spec/support/examples/mmd_all_meta.mmd +6 -0
  60. data/spec/support/examples/mmd_crazy_keys.mmd +8 -0
  61. data/spec/support/examples/mmd_crazy_tags.mmd +9 -0
  62. data/spec/support/examples/mmd_no_tags.mmd +1 -0
  63. data/spec/support/examples/mmd_with_tag.mmd +3 -0
  64. data/spec/support/examples/pdf_no_tags.pdf +0 -0
  65. data/spec/support/examples/pdf_with_tag.pdf +0 -0
  66. data/spec/support/examples/png_no_tags.png +0 -0
  67. data/spec/support/examples/png_with_tag.png +0 -0
  68. data/spec/support/examples/tex_no_tags.tex +10 -0
  69. data/spec/support/examples/tex_with_tag.tex +11 -0
  70. data/spec/support/examples/untaggable.txt +0 -0
  71. data/spec/support/examples.rb +32 -0
  72. data/spec/support/run_with_args.rb +36 -0
  73. data/spec/support/silence_stream.rb +12 -0
  74. data/spec/support/tag_handler_behavior.rb +125 -0
  75. data/stickyflag.gemspec +48 -0
  76. metadata +399 -0
@@ -0,0 +1,119 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'thor'
3
+ require 'open3'
4
+ require 'stickyflag/patches/tempfile_encoding'
5
+
6
+ module StickyFlag
7
+ module Tags
8
+ module PDF
9
+ module_function
10
+
11
+ def get(file_name, pdftk_path = 'pdftk')
12
+ stdout_str = ''
13
+ stderr_str = ''
14
+
15
+ begin
16
+ Open3.popen3(pdftk_path, file_name.to_s, 'dump_data_utf8') do |i, o, e, t|
17
+ out_reader = Thread.new { o.read }
18
+ err_reader = Thread.new { e.read }
19
+ i.close
20
+ stdout_str = out_reader.value
21
+ stderr_str = err_reader.value
22
+
23
+ stdout_str.force_encoding("UTF-8") if RUBY_VERSION >= "1.9.0"
24
+ stderr_str.force_encoding("UTF-8") if RUBY_VERSION >= "1.9.0"
25
+ end
26
+ rescue Exception
27
+ raise Thor::Error.new("ERROR: Failed to get tags for #{file_name}; pdftk call failed")
28
+ end
29
+ if stderr_str.start_with?("Error: ") || stderr_str.include?("Errno::ENOENT")
30
+ raise Thor::Error.new("ERROR: Failed to get tags for #{file_name}; pdftk call failed")
31
+ end
32
+
33
+ # More than one of these shouldn't be possible, but try to recover if
34
+ # it somehow happens.
35
+ matches = stdout_str.scan(/InfoKey: X-StickyFlag-Flags\nInfoValue: (.*?)\n/)
36
+ return [] if matches.empty?
37
+
38
+ tags = []
39
+
40
+ matches.each do |m|
41
+ match_string = m[0]
42
+ match_tags = match_string.split(',').map { |t| t.empty? ? nil : t.strip }.compact
43
+ next if match_tags.empty?
44
+
45
+ tags.concat(match_tags)
46
+ end
47
+
48
+ tags
49
+ end
50
+
51
+ def set(file_name, tag, pdftk_path = 'pdftk')
52
+ tags = get(file_name, pdftk_path)
53
+ return if tags.include? tag
54
+
55
+ tags << tag
56
+
57
+ info = Tempfile.new_with_encoding ['sfpdftag', '.txt']
58
+ begin
59
+ info.write("InfoKey: X-StickyFlag-Flags\n")
60
+ info.write("InfoValue: #{tags.join(', ')}\n")
61
+ info.close
62
+
63
+ outpath = File.tmpnam('.pdf')
64
+ ret = system(pdftk_path, file_name.to_s, 'update_info', info.path, 'output', outpath)
65
+ unless ret == true
66
+ raise Thor::Error.new("ERROR: Failed to set tag for #{file_name}; pdftk call failed")
67
+ end
68
+
69
+ FileUtils.mv outpath, file_name
70
+ ensure
71
+ info.unlink
72
+ end
73
+ end
74
+
75
+ def unset(file_name, tag, pdftk_path = 'pdftk')
76
+ tags = get(file_name, pdftk_path)
77
+ return unless tags.include? tag
78
+
79
+ tags.delete(tag)
80
+
81
+ info = Tempfile.new_with_encoding ['sfpdftag', '.txt']
82
+ begin
83
+ info.write("InfoKey: X-StickyFlag-Flags\n")
84
+ info.write("InfoValue: #{tags.join(', ')}\n")
85
+ info.close
86
+
87
+ outpath = File.tmpnam('.pdf')
88
+ ret = system(pdftk_path, file_name.to_s, 'update_info', info.path, 'output', outpath)
89
+ unless ret == true
90
+ raise Thor::Error.new("ERROR: Failed to unset tag for #{file_name}; pdftk call failed")
91
+ end
92
+
93
+ FileUtils.mv outpath, file_name
94
+ ensure
95
+ info.unlink
96
+ end
97
+ end
98
+
99
+ def clear(file_name, pdftk_path = 'pdftk')
100
+ info = Tempfile.new_with_encoding ['sfpdftag', '.txt']
101
+ begin
102
+ info.write("InfoKey: X-StickyFlag-Flags\n")
103
+ info.write("InfoValue: \n")
104
+ info.close
105
+
106
+ outpath = File.tmpnam('.pdf')
107
+ ret = system(pdftk_path, file_name.to_s, 'update_info', info.path, 'output', outpath)
108
+ unless ret == true
109
+ raise Thor::Error.new("ERROR: Failed to clear tags for #{file_name}; pdftk call failed")
110
+ end
111
+
112
+ FileUtils.mv outpath, file_name
113
+ ensure
114
+ info.unlink
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,61 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'thor'
3
+ begin
4
+ require 'oily_png'
5
+ rescue LoadError
6
+ require 'chunky_png'
7
+ end
8
+ require 'fileutils'
9
+
10
+ module StickyFlag
11
+ module Tags
12
+ module PNG
13
+ module_function
14
+
15
+ def get(file_name)
16
+ image = ChunkyPNG::Image.from_file(file_name)
17
+ tag_string = image.metadata['X-StickyFlag-Flags']
18
+ return [] if tag_string.nil?
19
+ tag_string.force_encoding('UTF-8') if RUBY_VERSION >= "1.9.0"
20
+ tag_string.split(',').map { |t| t.empty? ? nil : t.strip }.compact
21
+ end
22
+
23
+ def set(file_name, tag)
24
+ tags = get(file_name)
25
+ return if tags.include? tag
26
+
27
+ tags << tag
28
+
29
+ image = ChunkyPNG::Image.from_file(file_name)
30
+ image.metadata['X-StickyFlag-Flags'] = tags.join(', ')
31
+
32
+ outpath = File.tmpnam('.png')
33
+ image.save(outpath)
34
+ FileUtils.mv(outpath, file_name)
35
+ end
36
+
37
+ def unset(file_name, tag)
38
+ tags = get(file_name)
39
+ return unless tags.include? tag
40
+
41
+ tags.delete(tag)
42
+
43
+ image = ChunkyPNG::Image.from_file(file_name)
44
+ image.metadata['X-StickyFlag-Flags'] = tags.join(', ')
45
+
46
+ outpath = File.tmpnam('.png')
47
+ image.save(outpath)
48
+ FileUtils.mv(outpath, file_name)
49
+ end
50
+
51
+ def clear(file_name)
52
+ image = ChunkyPNG::Image.from_file(file_name)
53
+ image.metadata.delete('X-StickyFlag-Flags')
54
+
55
+ outpath = File.tmpnam('.png')
56
+ image.save(outpath)
57
+ FileUtils.mv(outpath, file_name)
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,99 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ module StickyFlag
4
+ module Tags
5
+ module SourceCode
6
+ module_function
7
+
8
+ #
9
+ # Specify:
10
+ # comment_line_regex: matches any line of comments at the start of the source code (when this doesn't match, we'll stop looking)
11
+ #
12
+ # tag_line_regex: matches the specific line that contains the tags, the one group in this regex should be the comma-separated list of tags
13
+ #
14
+ # tag_line_for(tags): convert the tag string (already a string!) into the output line we should print
15
+ #
16
+
17
+ def get(file_name)
18
+ File.open(file_name, 'r:UTF-8').each_line do |line|
19
+ return [] unless line =~ comment_line_regex
20
+
21
+ m = line.match(tag_line_regex)
22
+ if m
23
+ tag_string = m[1]
24
+ return [] if tag_string.nil? || tag_string.empty?
25
+ return tag_string.split(',').map { |t| t.empty? ? nil : t.strip }.compact
26
+ end
27
+ end
28
+
29
+ []
30
+ end
31
+
32
+ def set(file_name, tag)
33
+ tags = get(file_name)
34
+ return if tags.include? tag
35
+
36
+ tags << tag
37
+ set_tags = false
38
+
39
+ outpath = File.tmpnam
40
+ File.open(outpath, 'w:UTF-8') do |outfile|
41
+ File.open(file_name, 'r:UTF-8').each_line do |line|
42
+ if line !~ comment_line_regex
43
+ if set_tags == false
44
+ # We haven't set the tags yet, but the current line does *not*
45
+ # match the comment line regex. Add the tags line as a new line
46
+ # at the end of the comment block.
47
+ outfile.puts tag_line_for(tags.join(', '))
48
+ set_tags = true
49
+ else
50
+ outfile.puts line
51
+ end
52
+ else
53
+ if line =~ tag_line_regex
54
+ # Replace the old tag line with the new tag line
55
+ outfile.puts tag_line_for(tags.join(', '))
56
+ else
57
+ outfile.puts line
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ FileUtils.mv(outpath, file_name)
64
+ end
65
+
66
+ def unset(file_name, tag)
67
+ tags = get(file_name)
68
+ return unless tags.include? tag
69
+
70
+ tags.delete(tag)
71
+
72
+ outpath = File.tmpnam
73
+ File.open(outpath, 'w:UTF-8') do |outfile|
74
+ File.open(file_name, 'r:UTF-8').each_line do |line|
75
+ if line =~ tag_line_regex
76
+ outfile.puts tag_line_for(tags.join(', '))
77
+ else
78
+ outfile.puts line
79
+ end
80
+ end
81
+ end
82
+
83
+ FileUtils.mv(outpath, file_name)
84
+ end
85
+
86
+ def clear(file_name)
87
+ outpath = File.tmpnam
88
+ File.open(outpath, 'w:UTF-8') do |outfile|
89
+ File.open(file_name, 'r:UTF-8').each_line do |line|
90
+ next if line =~ tag_line_regex
91
+ outfile.puts line
92
+ end
93
+ end
94
+
95
+ FileUtils.mv(outpath, file_name)
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,25 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'stickyflag/tags/source_code'
3
+
4
+ module StickyFlag
5
+ module Tags
6
+ module TeX
7
+ module_function
8
+
9
+ def comment_line_regex
10
+ /\A% .*/
11
+ end
12
+
13
+ def tag_line_regex
14
+ /\A% SF_TAGS = (.*)/
15
+ end
16
+
17
+ def tag_line_for(str)
18
+ "% SF_TAGS = #{str}"
19
+ end
20
+
21
+ include SourceCode
22
+ module_function :get, :set, :unset, :clear
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,12 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ module StickyFlag
4
+ module Version
5
+ NUMBERS = [
6
+ MAJOR = 0,
7
+ MINOR = 2,
8
+ BUILD = 0
9
+ ]
10
+ end
11
+ VERSION = Version::NUMBERS.join('.')
12
+ end
data/lib/stickyflag.rb ADDED
@@ -0,0 +1,253 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ require 'rubygems'
4
+ require 'thor'
5
+ require 'backports'
6
+
7
+ require 'stickyflag/version'
8
+
9
+ require 'stickyflag/patches/tempfile_encoding'
10
+ require 'stickyflag/patches/tmpnam.rb'
11
+
12
+ require 'stickyflag/tags/source_code'
13
+ require 'stickyflag/tags/c'
14
+ require 'stickyflag/tags/mmd'
15
+ require 'stickyflag/tags/pdf'
16
+ require 'stickyflag/tags/png'
17
+ require 'stickyflag/tags/tex'
18
+
19
+ require 'stickyflag/configuration'
20
+ require 'stickyflag/paths'
21
+ require 'stickyflag/external_cmds'
22
+ require 'stickyflag/database'
23
+ require 'stickyflag/tag_factory'
24
+
25
+ module StickyFlag
26
+ class ThorApp < Thor
27
+ include Thor::Actions
28
+ class_option :color, :required => false, :default => true,
29
+ :desc => 'if true, print our status messages in color', :type => :boolean
30
+ class_option :force, :requires => false, :default => false, :aliases => '-f',
31
+ :desc => 'do not print diagnostic messages for missing files or empty tags on multiple-file operations'
32
+ class_option :quiet, :required => false, :default => false, :aliases => '-q',
33
+ :desc => 'if true, print only essential output to the console (skip empty tags, diagnostics)'
34
+
35
+ include Paths
36
+ include Configuration
37
+ include ExternalCmds
38
+ include TagFactory
39
+ include Database
40
+
41
+ def initialize(*args)
42
+ super
43
+
44
+ if options.color?
45
+ self.shell = Thor::Shell::Color.new
46
+ end
47
+
48
+ load_config!
49
+ find_external_cmds
50
+ load_database
51
+ end
52
+
53
+ desc 'config', "display and set configuration parameters"
54
+ long_desc <<-LONGDESC
55
+ `stickyflag config` allows you to set persistent configuration parameters
56
+ for StickyFlag.
57
+
58
+ With only --key <key> specified, display the current value for the given key.
59
+
60
+ With --key <key> <value>, set the value for the key.
61
+
62
+ With the --list option, list all available configuration parameters and
63
+ their current values.
64
+ LONGDESC
65
+ method_option :key, :aliases => '-k', :required => false,
66
+ :desc => 'the configuration key to set', :type => :string
67
+ method_option :list, :aliases => '-l', :default => false, :required => false,
68
+ :desc => 'list all available configuration options', :type => :boolean
69
+ method_option :reset, :default => false, :required => false,
70
+ :desc => 'reset *all* configuration settings to defaults', :type => :boolean
71
+ def config(value = nil)
72
+ if options.reset?
73
+ reset_config!
74
+ return
75
+ end
76
+
77
+ if options.list? || (options[:key].nil? && value.nil?)
78
+ dump_config
79
+ return
80
+ end
81
+
82
+ if options[:key].nil?
83
+ raise Thor::Error.new("ERROR: Cannot set a value without a key specified")
84
+ end
85
+
86
+ if value.nil?
87
+ value = get_config options[:key]
88
+ say "#{options[:key]}: '#{value}'"
89
+ return
90
+ end
91
+
92
+ set_config options[:key], value
93
+ say "'#{options[:key]}' set to '#{value}'" unless options.quiet?
94
+
95
+ save_config!
96
+ end
97
+
98
+ desc 'get [FILES]', "print the tags set for a set of files"
99
+ long_desc <<-LONGDESC
100
+ `stickyflag get` lets you look at the tags that have been applied to
101
+ a file or set of files.
102
+ LONGDESC
103
+ def get(*files)
104
+ if files.empty?
105
+ raise Thor::Error.new("stickyflag get requires at least 1 argument: \"stickyflag get [FILES]\"")
106
+ end
107
+
108
+ files.each do |file_name|
109
+ unless File.exist? file_name
110
+ say_status :error, "File #{file_name} does not exist", :red unless options.force? || options.quiet?
111
+ next
112
+ end
113
+
114
+ tags = get_tags_for file_name
115
+ if tags.empty?
116
+ say "#{file_name}: no tags" unless options.force? || options.quiet?
117
+ next
118
+ else
119
+ say "#{file_name}: #{tags.join(', ')}"
120
+ next
121
+ end
122
+ end
123
+ end
124
+
125
+
126
+ desc 'set [FILE] [TAG]', "set a tag for a file"
127
+ long_desc <<-LONGDESC
128
+ `stickyflag set` lets you add one particular tag to the tags present in a
129
+ given file. Specify the file you want to modify, and the tag you want to
130
+ add.
131
+ LONGDESC
132
+ def set(file_name, tag)
133
+ check_tag tag
134
+
135
+ unless File.exist? file_name
136
+ say_status :error, "File #{file_name} does not exist", :red unless options.quiet?
137
+ return
138
+ end
139
+
140
+ set_tag_for file_name, tag
141
+
142
+ tags = get_tags_for file_name
143
+ say_status :success, "New tags for #{file_name}: #{tags.join(', ')}", :green unless options.quiet?
144
+ end
145
+
146
+
147
+ desc 'unset [FILE] [TAG]', "remove a tag from a file"
148
+ long_desc <<-LONGDESC
149
+ `stickyflag unset` lets you delete one tag from the tags present in a file.
150
+ Specify the file you want to modify, and the tag you want to remove. This
151
+ action will fail if the tag is not set in the requested file.
152
+ LONGDESC
153
+ def unset(file_name, tag)
154
+ check_tag tag
155
+
156
+ unless File.exist? file_name
157
+ say_status :error, "File #{file_name} does not exist", :red unless options.quiet?
158
+ return
159
+ end
160
+
161
+ unset_tag_for file_name, tag
162
+
163
+ # Unsetting a tag might leave us with no tags at all, which makes this more
164
+ # complicated than the #set behavior
165
+ unless options.quiet?
166
+ tags = get_tags_for file_name
167
+ if tags.empty?
168
+ say_status :success, "New tags for #{file_name}: no tags", :green
169
+ else
170
+ say_status :success, "New tags for #{file_name}: #{tags.join(', ')}", :green
171
+ end
172
+ end
173
+ end
174
+
175
+
176
+ desc 'clear [FILES]', "remove all tags from a set of files"
177
+ long_desc <<-LONGDESC
178
+ `stickyflag clear` removes all tags that have been applied to the given
179
+ list of files.
180
+ LONGDESC
181
+ def clear(*files)
182
+ if files.empty?
183
+ raise Thor::Error.new("stickyflag clear requires at least 1 argument: \"stickyflag clear [FILES]\"")
184
+ end
185
+
186
+ files.each do |file_name|
187
+ unless File.exist? file_name
188
+ say_status :error, "File #{file_name} does not exist", :red unless options.force? || options.quiet?
189
+ return
190
+ end
191
+
192
+ clear_tags_for file_name
193
+ say_status :success, "Tags cleared for #{file_name}", :green unless options.quiet?
194
+ end
195
+ end
196
+
197
+ desc 'update', "update the tag database from the files on disk"
198
+ long_desc <<-LONGDESC
199
+ `stickyflag update` will read all files under the current directory (or
200
+ using the `root` configuration key) and refresh the database based on their
201
+ contents.
202
+ LONGDESC
203
+ def update
204
+ root = get_config(:root).strip
205
+ root = '.' if root.empty? || root.nil?
206
+
207
+ update_database_from_files root
208
+ end
209
+
210
+ desc 'tags', "show the list of currently used tags"
211
+ long_desc <<-LONGDESC
212
+ `stickyflag tags` shows the list of currently used tags as present in the
213
+ database. Note that this may be out of date with respect to the contents
214
+ of the disk, and can be refreshed using `stickyflag update`.
215
+ LONGDESC
216
+ def tags
217
+ say "Tags currently in use:" unless options.quiet?
218
+ padding = ''
219
+ padding = ' ' unless options.quiet?
220
+
221
+ tag_list.each do |t|
222
+ say "#{padding}#{t}"
223
+ end
224
+ end
225
+
226
+ desc 'find [TAG] [...]', "show all files that are tagged with the given tags"
227
+ long_desc <<-LONGDESC
228
+ `stickyflag find` locates all files that have a given tag or set of tags.
229
+ If multiple tags are provided, returned files must have all those tags.
230
+ LONGDESC
231
+ def find(*tags)
232
+ if tags.empty?
233
+ raise Thor::Error.new("stickyflag find requires at least 1 argument: \"stickyflag find [TAG] [...]\"")
234
+ end
235
+ tags.each { |t| check_tag t }
236
+
237
+ files_for_tags(tags).each do |file|
238
+ say file
239
+ end
240
+ end
241
+
242
+ private
243
+
244
+ def check_tag(tag)
245
+ if tag.include? ','
246
+ raise Thor::Error.new("ERROR: Tag names cannot include a comma.")
247
+ end
248
+ if tag.empty?
249
+ raise Thor::Error.new("ERROR: Cannot set an empty tag.")
250
+ end
251
+ end
252
+ end
253
+ end
@@ -0,0 +1,22 @@
1
+ # -*- encoding : utf-8 -*-
2
+ $KCODE = 'U' if RUBY_VERSION < "1.9.0"
3
+ ENV['RSPEC_TESTING'] = 'true'
4
+
5
+ require 'rubygems'
6
+ require 'bundler/setup'
7
+ require 'simplecov' unless ENV["CI"] == 'true'
8
+
9
+ require 'backports'
10
+ require 'rspec/autorun'
11
+ require 'stickyflag'
12
+
13
+ Dir['./spec/support/**/*.rb'].map { |f| require f }
14
+
15
+ RSpec.configure do |c|
16
+ c.before(:each) do
17
+ # Don't write anything to the console
18
+ Thor::Shell::Basic.any_instance.stub(:say) { }
19
+ Thor::Shell::Basic.any_instance.stub(:say_status) { }
20
+ end
21
+ end
22
+