frog 1.0.1

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.
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "frog"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'frog'
4
+ Frog.start
@@ -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,6 @@
1
+ class BrowserLauncher
2
+ def launch(target_link)
3
+ puts "Boom! Launching #{target_link}".green
4
+ Launchy.open(target_link)
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module Constants
2
+ VERSION = "1.0.1"
3
+ BASE_URL = "https://developer.android.com"
4
+ LINKS_URL = "https://developer.android.com/reference/lists.js"
5
+ end
@@ -0,0 +1,24 @@
1
+ class ExactSearcher
2
+ def initialize
3
+ @exiter = Exiter.new
4
+ end
5
+
6
+ def search (search_term, links)
7
+ # Grep the links array to exactly match our search term
8
+ filtered_links = links.grep(/\/#{search_term}.html\"/i)
9
+
10
+ # Handle error and return if we don't find anything
11
+ if filtered_links.empty?
12
+ @exiter.exit_due_to_doc_not_found
13
+ return
14
+ end
15
+
16
+ # Get the relative URL of the required class
17
+ relative_url = filtered_links[0].partition("link:\"").last.partition("\"").first
18
+
19
+ # Append to base URL to form complete URL
20
+ target_link = "#{Constants::BASE_URL}/#{relative_url}"
21
+
22
+ return target_link
23
+ end
24
+ end
@@ -0,0 +1,21 @@
1
+ class Exiter
2
+ def exit_due_to_no_search_term
3
+ abort "You need to provide something to search for".red
4
+ end
5
+
6
+ def exit_due_to_doc_not_found
7
+ abort "Sorry. It looks like we couldn't find what you were looking for".red
8
+ end
9
+
10
+ def exit_due_to_incorrect_index
11
+ abort "Sorry. It looks like you didn't enter the correct index".red
12
+ end
13
+
14
+ def exit_due_to_net_http_fail_during_links_update
15
+ exit
16
+ end
17
+
18
+ def exit_after_showing_help
19
+ exit
20
+ end
21
+ end
@@ -0,0 +1,32 @@
1
+ # Get the project root
2
+ lib = File.expand_path('../../lib', __FILE__)
3
+
4
+ # Add project root to LOAD_PATH
5
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
6
+
7
+ # Require everything in lib so we don't have to require
8
+ # them in each file
9
+ Dir.glob(lib + '/*', &method(:require))
10
+
11
+ # Require external and third party libs
12
+ require 'optparse'
13
+ require 'launchy'
14
+ require 'time'
15
+ require 'net/http'
16
+ require 'colorize'
17
+
18
+ module Frog
19
+ def self.start
20
+ options = OptionsGetter.new.get_options
21
+
22
+ search_term = SearchTermGetter.new.get_search_term
23
+
24
+ links = LinksGetter.new.get_links_from_file
25
+
26
+ target_link = SearchRouter.new.delegate_to_appropriate_searcher(options[:exact], search_term, links)
27
+
28
+ BrowserLauncher.new.launch(target_link)
29
+
30
+ LinksUpdater.new.update_links_if_needed
31
+ end
32
+ end
@@ -0,0 +1,77 @@
1
+ class FuzzySearcher
2
+ def initialize
3
+ @exiter = Exiter.new
4
+ end
5
+
6
+ def search (search_term, links)
7
+
8
+ # Grep the links array to fuzzily match our search term
9
+ filtered_links = links.grep(/#{search_term}/i)
10
+
11
+ # Error out and return if we don't find anything
12
+ if filtered_links.empty?
13
+ @exiter.exit_due_to_doc_not_found
14
+ return
15
+ end
16
+
17
+ # Create link and index hashes
18
+ # links_hash will map each class name to it's relative URL
19
+ # index_hash will match each selection index (that we show the user) to the class name
20
+ links_hash, index_hash = create_link_and_index_hashes(filtered_links)
21
+
22
+ # Show all the selection options to the user
23
+ show_selection_options(links_hash)
24
+
25
+ # Get the user selected index and verify if it's alright
26
+ index = get_verified_user_input(index_hash.size)
27
+
28
+ # Get the relative URL of the required class
29
+ relative_url = links_hash[index_hash[index]]
30
+
31
+ # Append to base URL to form complete URL
32
+ target_link = "#{Constants::BASE_URL}/#{relative_url}"
33
+
34
+ return target_link
35
+
36
+ end
37
+
38
+ def create_link_and_index_hashes(filtered_links)
39
+ # Create 2 hashes
40
+ links_hash = Hash.new
41
+ index_hash = Hash.new
42
+
43
+ filtered_links.each_with_index do |link, i|
44
+ # Get class name
45
+ class_name = link.partition("label:\"").last.partition("\"").first
46
+
47
+ # Get relative URL
48
+ class_url = link.partition("link:\"").last.partition("\"").first
49
+
50
+ # Map class name to relative URL
51
+ links_hash[class_name] = class_url
52
+
53
+ # Map index to class name
54
+ index_hash[i] = class_name
55
+ end
56
+
57
+ return links_hash, index_hash
58
+ end
59
+
60
+ def show_selection_options(links_hash)
61
+ puts "Enter the index of the docs you want. ex: Enter 1 if you wish to select the first option.".green
62
+ links_hash.keys.each_with_index do |class_name, i|
63
+ puts "#{i+1}: #{class_name}"
64
+ end
65
+ end
66
+
67
+ def get_verified_user_input(selection_options_size)
68
+ index = $stdin.gets.chomp.to_i - 1
69
+ if index < 0 || index >= selection_options_size
70
+ @exiter.exit_due_to_incorrect_index
71
+ return
72
+ end
73
+
74
+ return index
75
+ end
76
+
77
+ end
@@ -0,0 +1,7 @@
1
+ class LinksGetter
2
+ def get_links_from_file
3
+ contents = File.read(File.expand_path("../assets/lists.js", File.dirname(__FILE__)))
4
+
5
+ return contents.partition("[").last.partition("]").first.split("\n")
6
+ end
7
+ end
@@ -0,0 +1,49 @@
1
+ class LinksUpdater
2
+ attr_reader :timestamp_file_path, :links_file_path
3
+
4
+ def initialize
5
+ @timestamp_file_path = File.expand_path("../assets/last_updated.txt", File.dirname(__FILE__))
6
+ @links_file_path = File.expand_path("../assets/lists.js", File.dirname(__FILE__))
7
+ end
8
+
9
+ def update_links_if_needed
10
+ if is_time_to_update?
11
+ update_links_from_website
12
+ update_timestamp
13
+ end
14
+ end
15
+
16
+ private
17
+ def is_time_to_update?
18
+ timestamp = File.read(@timestamp_file_path)
19
+
20
+ last_updated = DateTime.parse(timestamp)
21
+
22
+ one_week_from_last_updated = last_updated + 7
23
+
24
+ return DateTime.now > one_week_from_last_updated
25
+ end
26
+
27
+ private
28
+ def update_links_from_website
29
+ begin
30
+ # Get the latest links from the website
31
+ puts "Indexing the latest docs...".green
32
+ response = Net::HTTP.get_response(URI.parse(Constants::LINKS_URL))
33
+ rescue StandardError
34
+ # Exit if links update fails
35
+ puts "Looks like there's an internet connection problem. Will try again later.".red
36
+ Exiter.new.exit_due_to_net_http_fail_during_links_update
37
+ return
38
+ end
39
+
40
+ # Write them to file
41
+ File.write(@links_file_path, response.body)
42
+ end
43
+
44
+ private
45
+ def update_timestamp
46
+ File.write(@timestamp_file_path, "#{DateTime.now}")
47
+ puts "Latest docs indexed!".green
48
+ end
49
+ end
@@ -0,0 +1,23 @@
1
+ class OptionsGetter
2
+ def initialize
3
+ @exiter = Exiter.new
4
+ @options = {exact: false}
5
+ @options_parser = OptionParser.new do |opts|
6
+ opts.banner = 'Usage: droiddocs.rb [options] search_term'
7
+
8
+ opts.on('-e', '--exact', 'Search for the exact class') do |v|
9
+ @options[:exact] = true
10
+ end
11
+
12
+ opts.on('-h', '--help', 'Displays Help') do
13
+ puts opts
14
+ @exiter.exit_after_showing_help
15
+ end
16
+ end
17
+ end
18
+
19
+ def get_options
20
+ @options_parser.parse!
21
+ return @options
22
+ end
23
+ end
@@ -0,0 +1,11 @@
1
+ class SearchRouter
2
+ def delegate_to_appropriate_searcher(exact, search_term, links)
3
+ if exact
4
+ # If it's an exact search
5
+ ExactSearcher.new.search(search_term, links)
6
+ else
7
+ # If it's a fuzzy search
8
+ FuzzySearcher.new.search(search_term, links)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ class SearchTermGetter
2
+ def get_search_term
3
+ search_term = ARGV[0]
4
+
5
+ if search_term.nil?
6
+ Exiter.new.exit_due_to_no_search_term
7
+ return
8
+ end
9
+
10
+ return search_term
11
+ end
12
+ end
metadata ADDED
@@ -0,0 +1,203 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: frog
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Anup Cowkur
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-06-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.12'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.12'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest-reporters
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.1'
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: 1.1.9
65
+ type: :development
66
+ prerelease: false
67
+ version_requirements: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - "~>"
70
+ - !ruby/object:Gem::Version
71
+ version: '1.1'
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: 1.1.9
75
+ - !ruby/object:Gem::Dependency
76
+ name: byebug
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '9.0'
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: 9.0.5
85
+ type: :development
86
+ prerelease: false
87
+ version_requirements: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - "~>"
90
+ - !ruby/object:Gem::Version
91
+ version: '9.0'
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: 9.0.5
95
+ - !ruby/object:Gem::Dependency
96
+ name: mocha
97
+ requirement: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - "~>"
100
+ - !ruby/object:Gem::Version
101
+ version: '1.1'
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: 1.1.0
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - "~>"
110
+ - !ruby/object:Gem::Version
111
+ version: '1.1'
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: 1.1.0
115
+ - !ruby/object:Gem::Dependency
116
+ name: launchy
117
+ requirement: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - "~>"
120
+ - !ruby/object:Gem::Version
121
+ version: '2.4'
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: 2.4.3
125
+ type: :runtime
126
+ prerelease: false
127
+ version_requirements: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '2.4'
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: 2.4.3
135
+ - !ruby/object:Gem::Dependency
136
+ name: colorize
137
+ requirement: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - "~>"
140
+ - !ruby/object:Gem::Version
141
+ version: '0.7'
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: 0.7.7
145
+ type: :runtime
146
+ prerelease: false
147
+ version_requirements: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - "~>"
150
+ - !ruby/object:Gem::Version
151
+ version: '0.7'
152
+ - - ">="
153
+ - !ruby/object:Gem::Version
154
+ version: 0.7.7
155
+ description:
156
+ email:
157
+ - anupcowkur89@gmail.com
158
+ executables:
159
+ - frog
160
+ extensions: []
161
+ extra_rdoc_files: []
162
+ files:
163
+ - assets/last_updated.txt
164
+ - assets/lists.js
165
+ - bin/console
166
+ - bin/frog
167
+ - bin/setup
168
+ - lib/browser_launcher.rb
169
+ - lib/constants.rb
170
+ - lib/exact_searcher.rb
171
+ - lib/exiter.rb
172
+ - lib/frog.rb
173
+ - lib/fuzzy_searcher.rb
174
+ - lib/links_getter.rb
175
+ - lib/links_updater.rb
176
+ - lib/options_getter.rb
177
+ - lib/search_router.rb
178
+ - lib/search_term_getter.rb
179
+ homepage: https://github.com/anupcowkur/frog
180
+ licenses:
181
+ - MIT
182
+ metadata: {}
183
+ post_install_message:
184
+ rdoc_options: []
185
+ require_paths:
186
+ - lib
187
+ required_ruby_version: !ruby/object:Gem::Requirement
188
+ requirements:
189
+ - - ">="
190
+ - !ruby/object:Gem::Version
191
+ version: '0'
192
+ required_rubygems_version: !ruby/object:Gem::Requirement
193
+ requirements:
194
+ - - ">="
195
+ - !ruby/object:Gem::Version
196
+ version: '0'
197
+ requirements: []
198
+ rubyforge_project:
199
+ rubygems_version: 2.6.4
200
+ signing_key:
201
+ specification_version: 4
202
+ summary: Frog helps you jump to the right Android dev docs from the command line
203
+ test_files: []