rhymera 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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..]
|