spoonerize 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/ruby.yml +24 -0
  3. data/.gitignore +1 -0
  4. data/Gemfile +7 -0
  5. data/LICENSE +21 -0
  6. data/README.md +106 -0
  7. data/Rakefile +19 -0
  8. data/_config.yml +1 -0
  9. data/bin/spoonerize +5 -0
  10. data/doc/README_md.html +200 -0
  11. data/doc/Spoonerize/Bumper.html +287 -0
  12. data/doc/Spoonerize/Cli.html +544 -0
  13. data/doc/Spoonerize/Log.html +362 -0
  14. data/doc/Spoonerize/Spoonerism.html +590 -0
  15. data/doc/Spoonerize.html +125 -0
  16. data/doc/created.rid +8 -0
  17. data/doc/css/fonts.css +167 -0
  18. data/doc/css/rdoc.css +619 -0
  19. data/doc/fonts/Lato-Light.ttf +0 -0
  20. data/doc/fonts/Lato-LightItalic.ttf +0 -0
  21. data/doc/fonts/Lato-Regular.ttf +0 -0
  22. data/doc/fonts/Lato-RegularItalic.ttf +0 -0
  23. data/doc/fonts/SourceCodePro-Bold.ttf +0 -0
  24. data/doc/fonts/SourceCodePro-Regular.ttf +0 -0
  25. data/doc/images/add.png +0 -0
  26. data/doc/images/arrow_up.png +0 -0
  27. data/doc/images/brick.png +0 -0
  28. data/doc/images/brick_link.png +0 -0
  29. data/doc/images/bug.png +0 -0
  30. data/doc/images/bullet_black.png +0 -0
  31. data/doc/images/bullet_toggle_minus.png +0 -0
  32. data/doc/images/bullet_toggle_plus.png +0 -0
  33. data/doc/images/date.png +0 -0
  34. data/doc/images/delete.png +0 -0
  35. data/doc/images/find.png +0 -0
  36. data/doc/images/loadingAnimation.gif +0 -0
  37. data/doc/images/macFFBgHack.png +0 -0
  38. data/doc/images/package.png +0 -0
  39. data/doc/images/page_green.png +0 -0
  40. data/doc/images/page_white_text.png +0 -0
  41. data/doc/images/page_white_width.png +0 -0
  42. data/doc/images/plugin.png +0 -0
  43. data/doc/images/ruby.png +0 -0
  44. data/doc/images/tag_blue.png +0 -0
  45. data/doc/images/tag_green.png +0 -0
  46. data/doc/images/transparent.png +0 -0
  47. data/doc/images/wrench.png +0 -0
  48. data/doc/images/wrench_orange.png +0 -0
  49. data/doc/images/zoom.png +0 -0
  50. data/doc/index.html +203 -0
  51. data/doc/js/darkfish.js +84 -0
  52. data/doc/js/navigation.js +105 -0
  53. data/doc/js/navigation.js.gz +0 -0
  54. data/doc/js/search.js +110 -0
  55. data/doc/js/search_index.js +1 -0
  56. data/doc/js/search_index.js.gz +0 -0
  57. data/doc/js/searcher.js +229 -0
  58. data/doc/js/searcher.js.gz +0 -0
  59. data/doc/table_of_contents.html +242 -0
  60. data/lib/config/lazy_words.yml +21 -0
  61. data/lib/spoonerize/bumper.rb +61 -0
  62. data/lib/spoonerize/cli.rb +158 -0
  63. data/lib/spoonerize/log.rb +68 -0
  64. data/lib/spoonerize/spoonerism.rb +166 -0
  65. data/lib/spoonerize/version.rb +5 -0
  66. data/lib/spoonerize.rb +21 -0
  67. data/pkg/spoonerize-0.0.7.gem +0 -0
  68. data/spoonerize.gemspec +38 -0
  69. metadata +154 -0
@@ -0,0 +1,158 @@
1
+ require 'optparse'
2
+ require 'yaml'
3
+
4
+ module Spoonerize
5
+ ##
6
+ # The class for handling the command-line interface.
7
+ class Cli
8
+
9
+ ##
10
+ # The preferences file the user can create to change runtime options.
11
+ #
12
+ # @return [String]
13
+ PREFERENCE_FILE =
14
+ File.expand_path(File.join(ENV['HOME'], '.spoonerize.yml')).freeze
15
+
16
+ ##
17
+ # Creates an instance of +StandupMD+ and runs what the user requested.
18
+ #
19
+ # @param [Array] options
20
+ def self.execute(options = [])
21
+ exe = new(options)
22
+
23
+ if exe.print?
24
+ exe.print_log
25
+ return
26
+ end
27
+
28
+ puts exe.spoonerism.to_s
29
+ exe.print_mappings if exe.map?
30
+
31
+ if exe.save?
32
+ puts "Saving..."
33
+ exe.spoonerism.save
34
+ end
35
+ end
36
+
37
+ ##
38
+ # Arguments passed at runtime.
39
+ #
40
+ # @return [Array] ARGV
41
+ attr_reader :options
42
+
43
+ ##
44
+ # Preferences after reading config file and parsing ARGV.
45
+ #
46
+ # @return [Array]
47
+ attr_reader :preferences
48
+
49
+ ##
50
+ # Create instance of +Cli+
51
+ #
52
+ # @param [Array] options
53
+ #
54
+ # @return [self]
55
+ def initialize(options)
56
+ @map = false
57
+ @save = false
58
+ @print = false
59
+ @options = options
60
+ @preferences = get_preferences
61
+ end
62
+
63
+ ##
64
+ # Sets up an instance of +Spoonerize::Spoonerism+ and passes all user
65
+ # preferences.
66
+ #
67
+ # @return [Spoonerize::Spoonerism]
68
+ def spoonerism
69
+ @spoonerism ||= ::Spoonerize::Spoonerism.new(options) do |s|
70
+ preferences.each { |k, v| s.send("#{k}=", v) }
71
+ end
72
+ end
73
+
74
+ ##
75
+ # Should we save to the log file?
76
+ #
77
+ # @return [Boolean]
78
+ def save?
79
+ @save
80
+ end
81
+
82
+ ##
83
+ # Should we print the mappings to the command line?
84
+ #
85
+ # @return [Boolean]
86
+ def map?
87
+ @map
88
+ end
89
+
90
+ ##
91
+ # Should we print to the command line?
92
+ #
93
+ # @return [Boolean]
94
+ def print?
95
+ @print
96
+ end
97
+
98
+ ##
99
+ # The length of the longest word in the phrase.
100
+ #
101
+ # @return [Integer]
102
+ def longest_word_length
103
+ @longest_word_length ||=
104
+ spoonerism.spoonerize.group_by(&:size).max.first.size
105
+ end
106
+
107
+ ##
108
+ # Print the log file contents to the command line.
109
+ #
110
+ # @return [nil]
111
+ def print_log
112
+ s = Spoonerize::Log.new(spoonerism.logfile_name)
113
+ s.each { |row| print row.join(' | ') + "\n" }
114
+ end
115
+
116
+ ##
117
+ # Print the hash of mappings to the command line.
118
+ #
119
+ # @return [nil]
120
+ def print_mappings
121
+ spoonerism.to_h.each do |k, v|
122
+ puts "%-#{longest_word_length}s => %s" % [k, v]
123
+ end
124
+ end
125
+
126
+ private
127
+
128
+ ##
129
+ # Read in args and set options
130
+ def get_preferences # :nodoc:
131
+ prefs = {}
132
+ OptionParser.new do |o|
133
+ o.version = ::Spoonerize::VERSION
134
+ o.on('-r', '--[no-]reverse', 'Reverse flipping') do |v|
135
+ prefs['reverse'] = v
136
+ end
137
+ o.on('-l', '--[no-]lazy', 'Skip small words') do |v|
138
+ prefs['lazy'] = v
139
+ end
140
+ o.on('-m', '--[no-]map', 'Print words mapping') do |v|
141
+ @map = v
142
+ end
143
+ o.on('-p', '--[no-]print', 'Print all entries in the log') do |v|
144
+ @print = v
145
+ end
146
+ o.on('-s', '--[no-]save', 'Save results in log') do |v|
147
+ @save = v
148
+ end
149
+ o.on('--exclude=WORDS', Array, 'Words to skip') do |v|
150
+ prefs['exclude'] = v
151
+ end
152
+ end.parse!(options)
153
+
154
+ (File.file?(PREFERENCE_FILE) ? YAML.load_file(PREFERENCE_FILE) : {})
155
+ .merge(prefs)
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,68 @@
1
+ require 'csv'
2
+ require 'fileutils'
3
+
4
+ module Spoonerize
5
+ ##
6
+ # Class that handles reading/writing logs.
7
+ class Log
8
+
9
+ ##
10
+ # The file name to use.
11
+ #
12
+ # @return [String]
13
+ attr_reader :file
14
+
15
+ ##
16
+ # The directory the file is located.
17
+ #
18
+ # @return [String]
19
+ attr_reader :directory
20
+
21
+ ##
22
+ # Constructor for Log.
23
+ #
24
+ # @param [String] file
25
+ #
26
+ # @return [Spoonerize::Log]
27
+ def initialize(file)
28
+ @file = File.expand_path(file)
29
+ @directory = File.dirname(file)
30
+ FileUtils.mkdir_p(directory) unless File.directory?(directory)
31
+ FileUtils.touch(file) unless File.file?(file)
32
+ end
33
+
34
+ ##
35
+ # The contents of the log file.
36
+ #
37
+ # @return [Array]
38
+ def contents
39
+ ::CSV.read(file)
40
+ end
41
+
42
+ ##
43
+ # Writes a line to the log.
44
+ #
45
+ # @param [Array] row
46
+ #
47
+ # @return [Array]
48
+ def write(row)
49
+ ::CSV.open(file, 'a') { |csv| csv << row }
50
+ end
51
+
52
+ ##
53
+ # Iterate through each line of the file.
54
+ #
55
+ # @return [Array]
56
+ def each
57
+ contents.each { |row| yield row }
58
+ end
59
+
60
+ ##
61
+ # Number of entries in the file.
62
+ #
63
+ # @return [Integer]
64
+ def size
65
+ contents.size
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,166 @@
1
+ module Spoonerize
2
+ ##
3
+ # The main word-flipper.
4
+ class Spoonerism
5
+
6
+ ##
7
+ # The words originally passed at initialization.
8
+ #
9
+ # @return [Array]
10
+ attr_reader :words
11
+
12
+ ##
13
+ # This boolean determines if flipping should be performed lazily.
14
+ #
15
+ # @param [Boolean] true if should be lazy.
16
+ #
17
+ # @return [Boolean]
18
+ attr_writer :lazy
19
+
20
+ ##
21
+ # This boolean determines if flipping should be reversed.
22
+ #
23
+ # @param [Boolean] true if should be reversed.
24
+ #
25
+ # @return [Boolean]
26
+ attr_writer :reverse
27
+
28
+ ##
29
+ # The full path to the log file.
30
+ #
31
+ # @param [String] file
32
+ #
33
+ # @return [String]
34
+ attr_accessor :logfile_name
35
+
36
+ ##
37
+ # The words that are to be excluded.
38
+ #
39
+ # @param [Array] words
40
+ #
41
+ # @return [Array]
42
+ attr_accessor :excluded_words
43
+
44
+ ##
45
+ # Initialize instance and raise if there aren't enough words to flip.
46
+ #
47
+ # @param [Array] words
48
+ def initialize(words)
49
+ @excluded_words = []
50
+ @words = words.map(&:downcase)
51
+ @lazy = false
52
+ @reverse = false
53
+ @logfile_name = File.expand_path(
54
+ File.join(ENV['HOME'], '.cache', 'spoonerize', 'spoonerize.csv')
55
+ )
56
+ yield self if block_given?
57
+ end
58
+
59
+ ##
60
+ # Iterates through words array, and maps its elements to the output of
61
+ # flip_words. Returns results as an array.
62
+ def spoonerize
63
+ raise JakPibError, 'Not enough words to flip' unless enough_flippable_words?
64
+ words.map.with_index { |word, idx| flip_words(word, idx) }
65
+ end
66
+
67
+ ##
68
+ # Returns spoonerize array as a joined string.
69
+ def to_s
70
+ spoonerize.join(' ')
71
+ end
72
+
73
+ ##
74
+ # Returns hash of the original words mapped to their flipped counterparts.
75
+ def to_h
76
+ Hash[words.zip(spoonerize)]
77
+ end
78
+
79
+ ##
80
+ # Same as to_h, but as json.
81
+ def to_json
82
+ to_h.to_json
83
+ end
84
+
85
+ ##
86
+ # Returns true if there are more than one non-excluded word to flip
87
+ def enough_flippable_words?
88
+ (words - all_excluded_words).size > 1
89
+ end
90
+
91
+ ##
92
+ # Should the lazy words be excluded?
93
+ def lazy?
94
+ @lazy
95
+ end
96
+
97
+ ##
98
+ # Should the words flip the other direction?
99
+ def reverse?
100
+ @reverse
101
+ end
102
+
103
+ ##
104
+ # Saves the flipped words to the log file, along with the options
105
+ def save
106
+ log.write([words.join(' '), to_s, options.join(', ')])
107
+ end
108
+
109
+ ##
110
+ # Returns an array of words to exclude by combining three arrays:
111
+ # * Any word in the passed arguments that's only one character
112
+ # * Any user-passed words, stored in +excluded_words+
113
+ # * If lazy-mode, the LAZY_WORDS from yaml file are added
114
+ def all_excluded_words
115
+ (excluded_words + (lazy? ? LAZY_WORDS : [])).map(&:downcase)
116
+ end
117
+
118
+ private
119
+
120
+ ##
121
+ # Main flipping method. Creates the replacement word from the next
122
+ # non-excluded word's leading syllables, and the current word's first vowels
123
+ # through the end of the word.
124
+ def flip_words(word, idx) # :nodoc:
125
+ return word if excluded?(idx)
126
+ bumper = Bumper.new(idx, words.size, reverse?)
127
+ bumper.bump until !excluded?(bumper.value)
128
+ words[bumper.value].match(consonants).to_s + word.match(vowels).to_s
129
+ end
130
+
131
+ ##
132
+ # Returns true if word[index] is in the excluded_words array
133
+ def excluded?(index) # :nodoc:
134
+ all_excluded_words.include?(words[index])
135
+ end
136
+
137
+ ##
138
+ # Returns regex to match first vowels through the rest of the word
139
+ def vowels # :nodoc:
140
+ /((?<!q)u|[aeio]|(?<=[bcdfghjklmnprstvwxz])y).*$/
141
+ end
142
+
143
+ ##
144
+ # Returns regex to match leading consonants
145
+ def consonants # :nodoc:
146
+ /^(y|[bcdfghjklmnprstvwxz]+|qu)/
147
+ end
148
+
149
+ ##
150
+ # Creates and memoizes instance of the log file.
151
+ def log # :nodoc:
152
+ @log ||= Spoonerize::Log.new(logfile_name)
153
+ end
154
+
155
+ ##
156
+ # the options as a string
157
+ def options # :nodoc:
158
+ o = []
159
+ o << 'Lazy' if lazy?
160
+ o << 'Reverse' if reverse?
161
+ o << 'Exclude [%s]' % [all_excluded_words.join(', ')] if excluded_words.any?
162
+ o << 'No Options' if o.empty?
163
+ o
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,5 @@
1
+ module Spoonerize
2
+ ##
3
+ # The version of the gem.
4
+ VERSION = '0.0.5'
5
+ end
data/lib/spoonerize.rb ADDED
@@ -0,0 +1,21 @@
1
+ require 'yaml'
2
+ require_relative 'spoonerize/spoonerism'
3
+ require_relative 'spoonerize/bumper'
4
+ require_relative 'spoonerize/version'
5
+ require_relative 'spoonerize/log'
6
+ require_relative 'spoonerize/cli'
7
+
8
+ ##
9
+ # The main namespace for the gem.
10
+ module Spoonerize
11
+ ##
12
+ # The error exception raised when there are not enough flippable words.
13
+ JakPibError = Class.new(StandardError)
14
+
15
+ ##
16
+ # Excluded words from config files.
17
+ LAZY_WORDS = YAML.load_file(
18
+ File.join(File.dirname(__FILE__), 'config', 'lazy_words.yml')
19
+ ).freeze
20
+ end
21
+
Binary file
@@ -0,0 +1,38 @@
1
+ require_relative 'lib/spoonerize/version'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = 'spoonerize'
5
+ spec.version = Spoonerize::VERSION
6
+ spec.authors = ['Evan Gray']
7
+ spec.email = 'evanthegrayt@vivaldi.net'
8
+ spec.license = 'MIT'
9
+ spec.date = Time.now.strftime('%Y-%m-%d')
10
+
11
+ spec.summary = %q{Spoonerize phrases from the command line.}
12
+ spec.description = %q{Spoonerize phrases from the command line. Comes with an API}
13
+ spec.homepage = 'https://evanthegrayt.github.io/spoonerize/'
14
+
15
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
16
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
17
+ if spec.respond_to?(:metadata)
18
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
19
+
20
+ spec.metadata['homepage_uri'] = spec.homepage
21
+ spec.metadata['source_code_uri'] = 'https://github.com/evanthegrayt/spoonerize'
22
+ spec.metadata['documentation_uri'] = 'https://evanthegrayt.github.io/spoonerize/doc/index.html'
23
+ else
24
+ raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.'
25
+ end
26
+
27
+ # Specify which files should be added to the gem when it is released.
28
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
29
+ # spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
30
+ # `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
31
+ # end
32
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
33
+ spec.bindir = 'bin'
34
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
35
+ spec.require_paths = ['lib']
36
+ spec.add_development_dependency 'rake', '~> 13.0', '>= 13.0.1'
37
+ spec.add_development_dependency 'test-unit', '~> 3.3', '>= 3.3.5'
38
+ end
metadata ADDED
@@ -0,0 +1,154 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: spoonerize
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.5
5
+ platform: ruby
6
+ authors:
7
+ - Evan Gray
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-05-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '13.0'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 13.0.1
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '13.0'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 13.0.1
33
+ - !ruby/object:Gem::Dependency
34
+ name: test-unit
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '3.3'
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 3.3.5
43
+ type: :development
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '3.3'
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 3.3.5
53
+ description: Spoonerize phrases from the command line. Comes with an API
54
+ email: evanthegrayt@vivaldi.net
55
+ executables:
56
+ - spoonerize
57
+ extensions: []
58
+ extra_rdoc_files: []
59
+ files:
60
+ - ".github/workflows/ruby.yml"
61
+ - ".gitignore"
62
+ - Gemfile
63
+ - LICENSE
64
+ - README.md
65
+ - Rakefile
66
+ - _config.yml
67
+ - bin/spoonerize
68
+ - doc/README_md.html
69
+ - doc/Spoonerize.html
70
+ - doc/Spoonerize/Bumper.html
71
+ - doc/Spoonerize/Cli.html
72
+ - doc/Spoonerize/Log.html
73
+ - doc/Spoonerize/Spoonerism.html
74
+ - doc/created.rid
75
+ - doc/css/fonts.css
76
+ - doc/css/rdoc.css
77
+ - doc/fonts/Lato-Light.ttf
78
+ - doc/fonts/Lato-LightItalic.ttf
79
+ - doc/fonts/Lato-Regular.ttf
80
+ - doc/fonts/Lato-RegularItalic.ttf
81
+ - doc/fonts/SourceCodePro-Bold.ttf
82
+ - doc/fonts/SourceCodePro-Regular.ttf
83
+ - doc/images/add.png
84
+ - doc/images/arrow_up.png
85
+ - doc/images/brick.png
86
+ - doc/images/brick_link.png
87
+ - doc/images/bug.png
88
+ - doc/images/bullet_black.png
89
+ - doc/images/bullet_toggle_minus.png
90
+ - doc/images/bullet_toggle_plus.png
91
+ - doc/images/date.png
92
+ - doc/images/delete.png
93
+ - doc/images/find.png
94
+ - doc/images/loadingAnimation.gif
95
+ - doc/images/macFFBgHack.png
96
+ - doc/images/package.png
97
+ - doc/images/page_green.png
98
+ - doc/images/page_white_text.png
99
+ - doc/images/page_white_width.png
100
+ - doc/images/plugin.png
101
+ - doc/images/ruby.png
102
+ - doc/images/tag_blue.png
103
+ - doc/images/tag_green.png
104
+ - doc/images/transparent.png
105
+ - doc/images/wrench.png
106
+ - doc/images/wrench_orange.png
107
+ - doc/images/zoom.png
108
+ - doc/index.html
109
+ - doc/js/darkfish.js
110
+ - doc/js/navigation.js
111
+ - doc/js/navigation.js.gz
112
+ - doc/js/search.js
113
+ - doc/js/search_index.js
114
+ - doc/js/search_index.js.gz
115
+ - doc/js/searcher.js
116
+ - doc/js/searcher.js.gz
117
+ - doc/table_of_contents.html
118
+ - lib/config/lazy_words.yml
119
+ - lib/spoonerize.rb
120
+ - lib/spoonerize/bumper.rb
121
+ - lib/spoonerize/cli.rb
122
+ - lib/spoonerize/log.rb
123
+ - lib/spoonerize/spoonerism.rb
124
+ - lib/spoonerize/version.rb
125
+ - pkg/spoonerize-0.0.7.gem
126
+ - spoonerize.gemspec
127
+ homepage: https://evanthegrayt.github.io/spoonerize/
128
+ licenses:
129
+ - MIT
130
+ metadata:
131
+ allowed_push_host: https://rubygems.org
132
+ homepage_uri: https://evanthegrayt.github.io/spoonerize/
133
+ source_code_uri: https://github.com/evanthegrayt/spoonerize
134
+ documentation_uri: https://evanthegrayt.github.io/spoonerize/doc/index.html
135
+ post_install_message:
136
+ rdoc_options: []
137
+ require_paths:
138
+ - lib
139
+ required_ruby_version: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ version: '0'
144
+ required_rubygems_version: !ruby/object:Gem::Requirement
145
+ requirements:
146
+ - - ">="
147
+ - !ruby/object:Gem::Version
148
+ version: '0'
149
+ requirements: []
150
+ rubygems_version: 3.1.2
151
+ signing_key:
152
+ specification_version: 4
153
+ summary: Spoonerize phrases from the command line.
154
+ test_files: []