rhymera 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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.
@@ -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
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rake/testtask"
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << "test"
8
+ t.libs << "lib"
9
+ t.test_files = FileList["test/**/*_test.rb"]
10
+ end
11
+
12
+ task default: :test
@@ -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__)
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/rhymera'
4
+ Rhymera::Menu.new.call
data/bin/run ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'rhymera'
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -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
@@ -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
@@ -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,11 @@
1
+ module Rhymera
2
+ # converts RhymeBrain json to object
3
+ class Rhyme
4
+ attr_reader :word, :syllables
5
+
6
+ def initialize(word:, syllables:)
7
+ @word = word
8
+ @syllables = syllables
9
+ end
10
+ end
11
+ 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
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rhymera
4
+ VERSION = '0.1.0'
5
+ end
@@ -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
@@ -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..]