rhymera 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.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.rspec +3 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +57 -0
- data/LICENSE +674 -0
- data/README.md +37 -0
- data/ROADMAP.md +101 -0
- data/Rakefile +12 -0
- data/bin/console +16 -0
- data/bin/rhymera +4 -0
- data/bin/run +5 -0
- data/bin/setup +8 -0
- data/lib/rhymera.rb +12 -0
- data/lib/rhymera/list.rb +50 -0
- data/lib/rhymera/menu.rb +82 -0
- data/lib/rhymera/portmanteau.rb +15 -0
- data/lib/rhymera/rhyme.rb +11 -0
- data/lib/rhymera/rhymebrain.rb +12 -0
- data/lib/rhymera/version.rb +5 -0
- data/rhymera.gemspec +43 -0
- data/scratch.rb +31 -0
- metadata +154 -0
data/README.md
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# Rhymera
|
2
|
+
|
3
|
+
Rhymera is a CLI gem to search the [RhymeBrain](https://rhymebrain.com) API for rhymes and portmanteaus of a given query. Menus give you the option to start a new search with the result, look through previous searches, or copy a result to the clipboard.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'rhymera'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle install
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install rhymera
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
Execute `rhymera`. After searching a query and choosing which type of search to conduct, you can find more information about each result in the menus.
|
24
|
+
|
25
|
+
## Development
|
26
|
+
|
27
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
28
|
+
|
29
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
30
|
+
|
31
|
+
## Contributing
|
32
|
+
|
33
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/revarcline/rhymera.
|
34
|
+
|
35
|
+
## License
|
36
|
+
|
37
|
+
Licensed under GPL 3.0, See LICENSE for details.
|
data/ROADMAP.md
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
RHYMERA
|
2
|
+
===
|
3
|
+
for api/scraper calls
|
4
|
+
[RhymeBrain](https://rhymebrain.com) for rhymes and portmanteaus
|
5
|
+
[clipboard](https://github.com/janlelis/clipboard) to copy result to clipboard
|
6
|
+
|
7
|
+
HEY OK DITCHING CLI/UI BECAUSE THEN YOU WON'T NEED THE DAMN HASH
|
8
|
+
like then you can just return objects
|
9
|
+
as cool as interactivity is it's not what they're looking for
|
10
|
+
|
11
|
+
make sure you go back to initializing list as array!
|
12
|
+
|
13
|
+
please research how to
|
14
|
+
a) take args from cli
|
15
|
+
b) paginate (should be easy) (also, its own method)
|
16
|
+
|
17
|
+
|
18
|
+
should probably review revision history of this document for blog post
|
19
|
+
of note:
|
20
|
+
initially wanted to add in scraper for OneLook but it was unscrapable (no js)
|
21
|
+
tried building with cli-ui gem from shopify so i could get a nice interactive prompt
|
22
|
+
however returning a string hobbled this - if i could understand the handlers better, maybe?
|
23
|
+
|
24
|
+
this way i can generate my list by iterating through each object enumerable
|
25
|
+
|
26
|
+
maybe switch to [TTY::Prompt](https://github.com/piotrmurach/tty-prompt)
|
27
|
+
i can keep my objects as arrays (clean, no redundancy)
|
28
|
+
and make my menus return the object value itself!
|
29
|
+
should be able to do this as a block!
|
30
|
+
|
31
|
+
ok! so blogpost about "picking the right depedencies"
|
32
|
+
- shopify's looked pretty fresh, liked the vi-keys functionality
|
33
|
+
- only returned string value though, meaning i would need to do some dumb iterations
|
34
|
+
- tty-prompt allowed me to more easily pass a hash
|
35
|
+
|
36
|
+
## basic outline:
|
37
|
+
|
38
|
+
present with
|
39
|
+
"Enter a word"
|
40
|
+
or "quit"
|
41
|
+
|
42
|
+
then, choose
|
43
|
+
1) rhyme
|
44
|
+
(type: getRhymes)
|
45
|
+
2) portmanteaus
|
46
|
+
(type: getPortmanteaus)
|
47
|
+
|
48
|
+
get a list of results back (possibly limit or paginate?)
|
49
|
+
|
50
|
+
|
51
|
+
detail view, common (module?)
|
52
|
+
- copy to clipboard
|
53
|
+
- search using word as query
|
54
|
+
- search previous query
|
55
|
+
- search a new query
|
56
|
+
- back to list
|
57
|
+
|
58
|
+
detail view - rhyme
|
59
|
+
word
|
60
|
+
number of syllables
|
61
|
+
|
62
|
+
detail view - portmanteau
|
63
|
+
portmanteau (actually spelling[0])
|
64
|
+
root word 1
|
65
|
+
root word 2 (selectable with common menu)
|
66
|
+
alternative (spelling[1] if spelling[1])
|
67
|
+
- selectable and switches with portmanteau name on selection (incl searchability)
|
68
|
+
|
69
|
+
## classes (and tests):
|
70
|
+
|
71
|
+
### Rhymera
|
72
|
+
- creates menu
|
73
|
+
- do i make everything extend it so i can call it from other stuff?
|
74
|
+
|
75
|
+
### Menu
|
76
|
+
- handles choices, relies on `TTY::Prompt`
|
77
|
+
- send word to clipboard with `Clipboard`
|
78
|
+
- displays `List` object as selectable menu
|
79
|
+
- also: search new word/previous search/search {other type}
|
80
|
+
- selecting `Rhyme` or `Portmanteau` entry shows relevant details, option to search
|
81
|
+
|
82
|
+
### List
|
83
|
+
- init with type (rhyme or port) and query
|
84
|
+
- has many `Rhyme`, `Portmanteau`
|
85
|
+
- collects the prior for display from a rhymebrain call
|
86
|
+
- class instance variable with prior queries!
|
87
|
+
|
88
|
+
### Rhyme
|
89
|
+
- contains each rhyme entry from json object
|
90
|
+
- syllables
|
91
|
+
|
92
|
+
### Portmanteau
|
93
|
+
- contains each portmanteau entry from json object
|
94
|
+
- spelling (array of one or two)
|
95
|
+
- source 1
|
96
|
+
- source 2
|
97
|
+
test:
|
98
|
+
make sure it parses input correctly, and `:alternative` is conditional on original object
|
99
|
+
|
100
|
+
### RhymeBrain
|
101
|
+
- uses input to structure api, scrapes rhymebrain results page, returns json
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'rhymera'
|
6
|
+
require_relative '../config/environment'
|
7
|
+
|
8
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
9
|
+
# with your gem easier. You can also use a different console, if you like.
|
10
|
+
|
11
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
12
|
+
# require "pry"
|
13
|
+
# Pry.start
|
14
|
+
|
15
|
+
require 'irb'
|
16
|
+
IRB.start(__FILE__)
|
data/bin/rhymera
ADDED
data/bin/run
ADDED
data/bin/setup
ADDED
data/lib/rhymera.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'rhymera/version'
|
4
|
+
require_relative 'rhymera/menu'
|
5
|
+
require_relative 'rhymera/list'
|
6
|
+
require_relative 'rhymera/rhymebrain'
|
7
|
+
require_relative 'rhymera/rhyme'
|
8
|
+
require_relative 'rhymera/portmanteau'
|
9
|
+
|
10
|
+
module Rhymera
|
11
|
+
class Error < StandardError; end
|
12
|
+
end
|
data/lib/rhymera/list.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
module Rhymera
|
2
|
+
# container for lists of Rhyme and Portmanteau
|
3
|
+
class List
|
4
|
+
attr_reader :query, :type, :object
|
5
|
+
attr_accessor :entries
|
6
|
+
|
7
|
+
@all = []
|
8
|
+
|
9
|
+
# using class instance variable instead of class variable per rubocop
|
10
|
+
class << self
|
11
|
+
attr_accessor :all
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(function:, word:)
|
15
|
+
@object = Rhymera::RhymeBrain.query(function: function, word: word)
|
16
|
+
@query = word
|
17
|
+
@type = function
|
18
|
+
@entries = []
|
19
|
+
build_correct_type
|
20
|
+
|
21
|
+
# add to all hash
|
22
|
+
self.class.all << self
|
23
|
+
end
|
24
|
+
|
25
|
+
def build_correct_type
|
26
|
+
case @type
|
27
|
+
when 'getRhymes'
|
28
|
+
create_rhymes
|
29
|
+
when 'getPortmanteaus'
|
30
|
+
create_portmanteaus
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def create_portmanteaus
|
35
|
+
@object.each do |entry|
|
36
|
+
port = Rhymera::Portmanteau.new(source: entry['source'],
|
37
|
+
combined: entry['combined'])
|
38
|
+
entries << port
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def create_rhymes
|
43
|
+
@object.each do |entry|
|
44
|
+
rhyme = Rhymera::Rhyme.new(word: entry['word'],
|
45
|
+
syllables: entry['syllables'])
|
46
|
+
entries << rhyme
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/rhymera/menu.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'clipboard'
|
2
|
+
require 'tty-prompt'
|
3
|
+
|
4
|
+
module Rhymera
|
5
|
+
# menu handler
|
6
|
+
class Menu
|
7
|
+
attr_accessor :list, :result, :word, :function
|
8
|
+
attr_reader :prompt
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@prompt = TTY::Prompt.new
|
12
|
+
# print once on intialization
|
13
|
+
puts 'Welcome to Rhymera.'
|
14
|
+
end
|
15
|
+
|
16
|
+
def call
|
17
|
+
@word = prompt.ask("Please enter a search term or :q to quit.\n>")
|
18
|
+
call if @word == ''
|
19
|
+
# vim-style quit, seems best
|
20
|
+
exit(0) if @word == ':q'
|
21
|
+
search(@word)
|
22
|
+
end
|
23
|
+
|
24
|
+
def search(term)
|
25
|
+
# can be called again and again!
|
26
|
+
@word = term
|
27
|
+
@function = search_type
|
28
|
+
@list = Rhymera::List.new(word: @word, function: "get#{@function}")
|
29
|
+
display_results
|
30
|
+
end
|
31
|
+
|
32
|
+
def search_type
|
33
|
+
prompt.select('Which type of result are you looking for?',
|
34
|
+
%w[Rhymes Portmanteaus])
|
35
|
+
end
|
36
|
+
|
37
|
+
def display_results
|
38
|
+
# can be called both by search and previous entries
|
39
|
+
results = extra_menu_entries
|
40
|
+
results << @list.entries.map { |ent| { ent.word.to_s => ent } }
|
41
|
+
result = prompt.select("#{@function} for '#{@word}' and other options:", results)
|
42
|
+
|
43
|
+
@word = result.word
|
44
|
+
detail_view(result)
|
45
|
+
end
|
46
|
+
|
47
|
+
def extra_menu_entries
|
48
|
+
# options leading to lambas! we love lambdas, don't we folks
|
49
|
+
[{ "Copy '#{@word}' to Clipboard" => -> { Clipboard.copy(@word) } },
|
50
|
+
{ "Search '#{@word}'" => -> { search(@word) } },
|
51
|
+
{ 'New Search' => -> { call } },
|
52
|
+
{ 'Previous Searches' => -> { old_searches } },
|
53
|
+
{ 'Quit Program' => -> { exit(0) } }]
|
54
|
+
end
|
55
|
+
|
56
|
+
def detail_view(object)
|
57
|
+
menu = extra_menu_entries
|
58
|
+
# iterate through attrs of a given Rhyme or Portmanteau for display
|
59
|
+
object.instance_variables.each do |var|
|
60
|
+
arg = var.to_s.gsub('@', '')
|
61
|
+
word = object.send(arg)
|
62
|
+
menu << { "#{arg.capitalize}: #{word}" => word }
|
63
|
+
end
|
64
|
+
opts = prompt.select("More details on #{@word}:", menu)
|
65
|
+
|
66
|
+
@word = opts
|
67
|
+
prompt.select("More details on #{@word}:", extra_menu_entries)
|
68
|
+
end
|
69
|
+
|
70
|
+
def old_searches
|
71
|
+
# here's one of the ol' class methods
|
72
|
+
lists = Rhymera::List.all.map do |list|
|
73
|
+
{ "#{list.type[3..]} for #{list.query}" => list }
|
74
|
+
end
|
75
|
+
selection = prompt.select('Previous searches:', lists)
|
76
|
+
@list = selection
|
77
|
+
@function = selection.type[3..]
|
78
|
+
@word = selection.query
|
79
|
+
display_results
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Rhymera
|
2
|
+
# converts RhymeBrain json data to object
|
3
|
+
class Portmanteau
|
4
|
+
attr_reader :prefix, :suffix, :word, :alternative
|
5
|
+
|
6
|
+
def initialize(source:, combined:)
|
7
|
+
source_words = source.split(',')
|
8
|
+
combined_words = combined.split(',')
|
9
|
+
@prefix = source_words[0]
|
10
|
+
@suffix = source_words[1]
|
11
|
+
@word = combined_words[0]
|
12
|
+
@alternative = combined_words[1] if combined_words[1]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Rhymera
|
5
|
+
# calls Rhymebrain API via URL, gets JSON object
|
6
|
+
class RhymeBrain
|
7
|
+
def self.query(function:, word:)
|
8
|
+
uri = URI.parse("https://rhymebrain.com/talk?function=#{function}&word=#{word}")
|
9
|
+
JSON.parse(Net::HTTP.get(uri))
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/rhymera.gemspec
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lib/rhymera/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'rhymera'
|
7
|
+
spec.version = Rhymera::VERSION
|
8
|
+
spec.authors = ['Alex Cline']
|
9
|
+
spec.email = ['rev.a.r.cline@gmail.com']
|
10
|
+
|
11
|
+
spec.summary = 'rhyme and portmanteau generator'
|
12
|
+
spec.description = 'uses RhymeBrain api to find rhymes and portmanteaus'
|
13
|
+
spec.homepage = 'https://github.com/revarcline/rhymera'
|
14
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 2.6.1')
|
15
|
+
|
16
|
+
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
17
|
+
|
18
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
19
|
+
spec.metadata['source_code_uri'] = 'https://github.com/revarcline/rhymera.git'
|
20
|
+
spec.metadata['changelog_uri'] = 'https://github.com/revarcline/rhymera/blob/main/CHANGELOG.md'
|
21
|
+
|
22
|
+
# Specify which files should be added to the gem when it is released.
|
23
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
24
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
25
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
|
26
|
+
end
|
27
|
+
spec.bindir = 'bin'
|
28
|
+
spec.executables = %w[rhymera]
|
29
|
+
spec.require_paths = %w[lib bin]
|
30
|
+
|
31
|
+
# Uncomment to register a new dependency of your gem
|
32
|
+
# spec.add_dependency "example-gem", "~> 1.0"
|
33
|
+
spec.add_dependency 'clipboard', '~> 1.3'
|
34
|
+
spec.add_dependency 'tty-prompt', '~> 0.23'
|
35
|
+
|
36
|
+
spec.add_development_dependency 'bundler', '~> 2.2'
|
37
|
+
spec.add_development_dependency 'pry'
|
38
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
39
|
+
spec.add_development_dependency 'rspec', '~> 3.9'
|
40
|
+
|
41
|
+
# For more information and examples about making a new gem, checkout our
|
42
|
+
# guide at: https://bundler.io/guides/creating_gem.html
|
43
|
+
end
|
data/scratch.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'tty-prompt'
|
2
|
+
require_relative 'lib/rhymera'
|
3
|
+
prompt = TTY::Prompt.new
|
4
|
+
port_list = Rhymera::List.new(function: 'getPortmanteaus', word: 'fancy')
|
5
|
+
|
6
|
+
prompt.yes?('is this working?')
|
7
|
+
|
8
|
+
prompt.select('Select a result for more info',
|
9
|
+
port_list.entries.map(&:word))
|
10
|
+
|
11
|
+
object = prompt.select('Select a result for more info',
|
12
|
+
port_list.entries.map { |entry| { entry.word.to_s => entry } })
|
13
|
+
|
14
|
+
object.instance_variables
|
15
|
+
|
16
|
+
object.instance_variables.first.to_s.gsub('@', '')
|
17
|
+
|
18
|
+
object.source_one
|
19
|
+
|
20
|
+
object.instance_variables.each do |var|
|
21
|
+
arg = var.to_s.gsub('@', '')
|
22
|
+
puts "#{arg.capitalize}: #{object.send(arg)}"
|
23
|
+
end
|
24
|
+
|
25
|
+
Rhymera::List.all
|
26
|
+
|
27
|
+
Rhymera::List.all.first.class.to_s.split('::')[1]
|
28
|
+
Rhymera::List.all.first.entries.first.word
|
29
|
+
|
30
|
+
Rhymera::List.all.first.query
|
31
|
+
Rhymera::List.all.first.type[3..]
|