mdn_query 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 +9 -0
- data/.rubocop.yml +34 -0
- data/.travis.yml +16 -0
- data/Gemfile +4 -0
- data/LICENSE.md +25 -0
- data/README.md +150 -0
- data/Rakefile +18 -0
- data/bin/mdn-query +79 -0
- data/lib/mdn_query.rb +77 -0
- data/lib/mdn_query/document.rb +36 -0
- data/lib/mdn_query/entry.rb +62 -0
- data/lib/mdn_query/errors.rb +42 -0
- data/lib/mdn_query/list.rb +82 -0
- data/lib/mdn_query/search.rb +111 -0
- data/lib/mdn_query/search_result.rb +69 -0
- data/lib/mdn_query/section.rb +98 -0
- data/lib/mdn_query/table.rb +114 -0
- data/lib/mdn_query/traverse_dom.rb +176 -0
- data/lib/mdn_query/version.rb +4 -0
- data/mdn_query.gemspec +37 -0
- data/screenshots/demo.gif +0 -0
- metadata +234 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 80ea4f6f65d473f50f9f4c14a06137c4c8a33231
|
4
|
+
data.tar.gz: 893ee7f7c9439f46f84e27de7c44f2958b276f3b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 156b7420731927a3c003014c4fdba0628cb24ffcdb5660ae6f1bab2844b2f3228b4aa40dcd5066fdfa3c7885a92d720961c69b7db989ea0508232ad6d9d56e2d
|
7
|
+
data.tar.gz: 487e05bf5a4968c63f512ec86393f8b4a8b43069d0a87f8bef4dfca6fab986cc01f0a111717044d06d57fd962ee20f43d360660ebc0442c33bad6e93e4322c45
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
Metrics/BlockLength:
|
2
|
+
CountComments: false
|
3
|
+
Max: 25
|
4
|
+
Exclude:
|
5
|
+
- mdn_query.gemspec
|
6
|
+
- lib/mdn_query/traverse_dom.rb
|
7
|
+
Metrics/ClassLength:
|
8
|
+
CountComments: false
|
9
|
+
Max: 100
|
10
|
+
Exclude:
|
11
|
+
- test/**/*.rb
|
12
|
+
- lib/mdn_query/traverse_dom.rb
|
13
|
+
Metrics/ModuleLength:
|
14
|
+
CountComments: false
|
15
|
+
Max: 100
|
16
|
+
Exclude:
|
17
|
+
- test/**/*.rb
|
18
|
+
Metrics/AbcSize:
|
19
|
+
Max: 20
|
20
|
+
Exclude:
|
21
|
+
- lib/mdn_query/traverse_dom.rb
|
22
|
+
Metrics/CyclomaticComplexity:
|
23
|
+
Max: 10
|
24
|
+
Exclude:
|
25
|
+
- lib/mdn_query/traverse_dom.rb
|
26
|
+
Metrics/MethodLength:
|
27
|
+
CountComments: false
|
28
|
+
Max: 25
|
29
|
+
Exclude:
|
30
|
+
- lib/mdn_query/traverse_dom.rb
|
31
|
+
Metrics/PerceivedComplexity:
|
32
|
+
Max: 10
|
33
|
+
Exclude:
|
34
|
+
- lib/mdn_query/traverse_dom.rb
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.md
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
=====================
|
3
|
+
|
4
|
+
Copyright © 2016 Michael Jungo
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person
|
7
|
+
obtaining a copy of this software and associated documentation
|
8
|
+
files (the “Software”), to deal in the Software without
|
9
|
+
restriction, including without limitation the rights to use,
|
10
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11
|
+
copies of the Software, and to permit persons to whom the
|
12
|
+
Software is furnished to do so, subject to the following
|
13
|
+
conditions:
|
14
|
+
|
15
|
+
The above copyright notice and this permission notice shall be
|
16
|
+
included in all copies or substantial portions of the Software.
|
17
|
+
|
18
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
|
19
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
20
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
22
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
23
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
24
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
25
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
# MdnQuery
|
2
|
+
|
3
|
+
[![Build Status][travis-img]][travis]
|
4
|
+
|
5
|
+
Query the [Mozilla Developer Network][mdn] documentation. Unfortunately they do
|
6
|
+
not provide an API to fetch the documentation entries, which means that all
|
7
|
+
informations are extracted from the HTML pages to create a Markdown-like
|
8
|
+
representation. Another drawback is that it requires two network requests to
|
9
|
+
retrieve a single entry based on a search term, which is frequently desired as
|
10
|
+
a precise search term almost always yields the concrete entry as the first
|
11
|
+
result.
|
12
|
+
|
13
|
+
## CLI
|
14
|
+
|
15
|
+
The binary `mdn-query` provides an interactive command line interface to easily
|
16
|
+
search a query. By default it only searches for results in the JavaScript topic.
|
17
|
+
|
18
|
+
```
|
19
|
+
Usage: mdn-query [options] <search-term>
|
20
|
+
|
21
|
+
Options:
|
22
|
+
-v, --version Shows the program's version
|
23
|
+
-h, --help Shows this help message
|
24
|
+
-f, --first, --first-match Returns the first match instead of a list
|
25
|
+
-o, --open, --open-browser Opens the appropriate page in the default web browser
|
26
|
+
-t, --topics The topics to search in, delimited by commas
|
27
|
+
```
|
28
|
+
|
29
|
+
### Examples
|
30
|
+
|
31
|
+
```sh
|
32
|
+
mdn-query bind # Searches for 'bind'
|
33
|
+
mdn-query bind --first # Retrieves first match of the search result
|
34
|
+
mdn-query bind --open # Opens the search results in the default browser
|
35
|
+
mdn-query bind --first --open # Opens the first match in the default browser
|
36
|
+
mdn-query bind --topics js,css # Searches in the topics 'js' and 'css'
|
37
|
+
```
|
38
|
+
|
39
|
+
### Demo
|
40
|
+
|
41
|
+
![Demo][demo]
|
42
|
+
|
43
|
+
## Library
|
44
|
+
|
45
|
+
### Top level methods
|
46
|
+
|
47
|
+
The following methods, that each take the search query and optional search
|
48
|
+
options as parameters, cover the most common use cases:
|
49
|
+
|
50
|
+
#### MdnQuery.list(query, options)
|
51
|
+
|
52
|
+
Creates a list with the search results. The entries in the list do not yet
|
53
|
+
contain the content of the corresponding documentation entries. They need to be
|
54
|
+
fetched individually.
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
list = MdnQuery.list('bind')
|
58
|
+
# Searches in the topics 'js' and 'css'
|
59
|
+
list = MdnQuery.list('bind', topics: ['js', 'css'])
|
60
|
+
# Prints a numbered list of the search result with a small description
|
61
|
+
puts list
|
62
|
+
# Finds all items that include 'Object' in their title
|
63
|
+
object_entries = list.items.select { |e| e.title =~ /Object/ }
|
64
|
+
```
|
65
|
+
|
66
|
+
#### MdnQuery.first_match(query, options)
|
67
|
+
|
68
|
+
Retrieves the content of the first entry of the search results. This requires
|
69
|
+
two network requests, because it is required to first search the Mozilla
|
70
|
+
Developer Network and then fetch the page of the respective entry.
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
content = MdnQuery.first_match('bind')
|
74
|
+
# Prints a Markdown-like representation of the entry
|
75
|
+
puts content
|
76
|
+
```
|
77
|
+
|
78
|
+
#### MdnQuery.open_list(query, options)
|
79
|
+
|
80
|
+
Opens the search query in the default web browser instead of retrieving the
|
81
|
+
results, therefore there is no network request made.
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
MdnQuery.open_list('bind')
|
85
|
+
```
|
86
|
+
|
87
|
+
#### MdnQuery.open_first_match(query, options)
|
88
|
+
|
89
|
+
Opens the first entry in the default web browser instead of fetching the
|
90
|
+
corresponding page. This means there is only one network request to retrieve the
|
91
|
+
list of search results.
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
MdnQuery.open_first_match('bind')
|
95
|
+
```
|
96
|
+
|
97
|
+
### Search
|
98
|
+
|
99
|
+
```ruby
|
100
|
+
# Creates a new search that is not executed yet
|
101
|
+
search = MdnQuery::Search.new('bind', topics: ['js', 'css'])
|
102
|
+
# Opens the search results in the default web browser
|
103
|
+
search.open
|
104
|
+
# Executes the search request
|
105
|
+
search.execute
|
106
|
+
# Creates a list of the search results
|
107
|
+
list = search.result.to_list
|
108
|
+
```
|
109
|
+
|
110
|
+
A search result can contain multiple pages. To easily navigate through the
|
111
|
+
pages, the methods `next_page` and `previous_page` are available, that retrieve
|
112
|
+
the next and previous page respectively, if it exists.
|
113
|
+
|
114
|
+
```ruby
|
115
|
+
# Retrieves the next page of the search results
|
116
|
+
search.next_page
|
117
|
+
# Retrieves the previous page of the search results
|
118
|
+
search.previous_page
|
119
|
+
```
|
120
|
+
|
121
|
+
### Entry
|
122
|
+
|
123
|
+
The content of an entry can be retrieved with the method `content`, which
|
124
|
+
fetches the documentation entry once, and simply returns it on further calls.
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
list = MdnQuery.list('bind', topics: ['js', 'css'])
|
128
|
+
entry = list.first
|
129
|
+
# Opens the entry in the default web browser
|
130
|
+
entry.open
|
131
|
+
# Prints the entry's content, performing a network request
|
132
|
+
puts entry.content
|
133
|
+
# Prints the content again without another network request
|
134
|
+
puts entry.content
|
135
|
+
```
|
136
|
+
|
137
|
+
## Contributing
|
138
|
+
|
139
|
+
Bug reports and pull requests are welcome on [GitHub][github-repo].
|
140
|
+
|
141
|
+
## License
|
142
|
+
|
143
|
+
The gem is available as open source under the terms of the [MIT License][mit].
|
144
|
+
|
145
|
+
[demo]: screenshots/demo.gif
|
146
|
+
[github-repo]: https://github.com/jungomi/mdn-query
|
147
|
+
[mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript
|
148
|
+
[mit]: http://opensource.org/licenses/MIT
|
149
|
+
[travis]: https://travis-ci.org/jungomi/mdn_query
|
150
|
+
[travis-img]: https://travis-ci.org/jungomi/mdn_query.svg?branch=master
|
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'mdn_query'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rubocop/rake_task'
|
5
|
+
|
6
|
+
Rake::TestTask.new(:test) do |t|
|
7
|
+
t.libs << 'test'
|
8
|
+
t.libs << 'lib'
|
9
|
+
t.test_files = if ARGV.size > 1
|
10
|
+
FileList[*ARGV[1..-1]]
|
11
|
+
else
|
12
|
+
FileList['test/**/*_test.rb']
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
RuboCop::RakeTask.new(:lint)
|
17
|
+
|
18
|
+
task default: [:lint, :test]
|
data/bin/mdn-query
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
lib = File.expand_path('../../lib', __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
|
6
|
+
require 'mdn_query'
|
7
|
+
require 'launchy'
|
8
|
+
require 'slop'
|
9
|
+
require 'tty-pager'
|
10
|
+
require 'tty-prompt'
|
11
|
+
|
12
|
+
prompt = TTY::Prompt.new
|
13
|
+
pager = TTY::Pager.new
|
14
|
+
|
15
|
+
opts = Slop.parse do |o|
|
16
|
+
o.banner = 'Usage: mdn-query [options] <search-term>'
|
17
|
+
o.separator ''
|
18
|
+
o.separator 'Options:'
|
19
|
+
o.on '-v', '--version', "Shows the program's version" do
|
20
|
+
puts MdnQuery::VERSION
|
21
|
+
end
|
22
|
+
o.on '-h', '--help', 'Shows this help message' do
|
23
|
+
prompt.say o
|
24
|
+
exit
|
25
|
+
end
|
26
|
+
o.bool '-f', '--first', '--first-match',
|
27
|
+
'Returns the first match instead of a list'
|
28
|
+
o.bool '-o', '--open', '--open-browser',
|
29
|
+
'Opens the appropriate page in the default web browser'
|
30
|
+
o.array '-t', '--topics',
|
31
|
+
'The topics to search in, delimited by commas'
|
32
|
+
end
|
33
|
+
|
34
|
+
if opts.arguments.empty?
|
35
|
+
prompt.say opts
|
36
|
+
exit
|
37
|
+
end
|
38
|
+
|
39
|
+
search_term = opts.arguments.join(' ')
|
40
|
+
topics = opts[:topics]
|
41
|
+
topics = ['js'] if topics.empty?
|
42
|
+
|
43
|
+
case [opts.first?, opts.open?]
|
44
|
+
when [true, true]
|
45
|
+
begin
|
46
|
+
MdnQuery.open_first_match(search_term, topics: topics)
|
47
|
+
rescue MdnQuery::NoEntryFound => e
|
48
|
+
prompt.say e.message
|
49
|
+
exit
|
50
|
+
end
|
51
|
+
when [true, false]
|
52
|
+
begin
|
53
|
+
pager.page MdnQuery.first_match(search_term, topics: topics)
|
54
|
+
rescue MdnQuery::NoEntryFound => e
|
55
|
+
prompt.say e.message
|
56
|
+
exit
|
57
|
+
end
|
58
|
+
when [false, true]
|
59
|
+
MdnQuery.open_list(search_term, topics: topics)
|
60
|
+
when [false, false]
|
61
|
+
begin
|
62
|
+
list = MdnQuery.list(search_term, topics: topics)
|
63
|
+
rescue MdnQuery::NoEntryFound
|
64
|
+
prompt.say "No results for '#{search_term}'"
|
65
|
+
exit
|
66
|
+
end
|
67
|
+
begin
|
68
|
+
selected_entry = prompt.select("Results for '#{search_term}'") do |menu|
|
69
|
+
menu.enum ')'
|
70
|
+
list.each do |entry|
|
71
|
+
menu.choice entry.title, entry
|
72
|
+
end
|
73
|
+
end
|
74
|
+
pager.page selected_entry.content
|
75
|
+
rescue TTY::Prompt::Reader::InputInterrupt
|
76
|
+
puts
|
77
|
+
exit
|
78
|
+
end
|
79
|
+
end
|
data/lib/mdn_query.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'English'
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'launchy'
|
4
|
+
require 'rest-client'
|
5
|
+
|
6
|
+
require 'mdn_query/document'
|
7
|
+
require 'mdn_query/entry'
|
8
|
+
require 'mdn_query/errors'
|
9
|
+
require 'mdn_query/list'
|
10
|
+
require 'mdn_query/search_result'
|
11
|
+
require 'mdn_query/search'
|
12
|
+
require 'mdn_query/section'
|
13
|
+
require 'mdn_query/table'
|
14
|
+
require 'mdn_query/traverse_dom'
|
15
|
+
require 'mdn_query/version'
|
16
|
+
|
17
|
+
# Query the Mozilla Developer Network documentation.
|
18
|
+
module MdnQuery
|
19
|
+
# The base url for the search queries.
|
20
|
+
BASE_URL = 'https://developer.mozilla.org/search'.freeze
|
21
|
+
|
22
|
+
# Searches the given query and creates a list with the results.
|
23
|
+
#
|
24
|
+
# @param query [String] the query to search for
|
25
|
+
# @param options [Hash] additional query options (see
|
26
|
+
# {MdnQuery::Search#initialize})
|
27
|
+
# @raise [MdnQuery::HttpRequestFailed] if a HTTP request fails
|
28
|
+
# @raise [MdnQuery::NoEntryFound] if no entry was found
|
29
|
+
# @return [MdnQuery::List] the list of results
|
30
|
+
def self.list(query, options = {})
|
31
|
+
search = MdnQuery::Search.new(query, options)
|
32
|
+
list = search.execute.to_list
|
33
|
+
if list.empty?
|
34
|
+
raise MdnQuery::NoEntryFound.new(query, options), 'No entry found'
|
35
|
+
end
|
36
|
+
list
|
37
|
+
end
|
38
|
+
|
39
|
+
# Searches the given query and returns the first fetched entry in the list.
|
40
|
+
#
|
41
|
+
# @param query [String] the query to search for
|
42
|
+
# @param options [Hash] additional query options (see
|
43
|
+
# {MdnQuery::Search#initialize})
|
44
|
+
# @raise [MdnQuery::HttpRequestFailed] if a HTTP request fails
|
45
|
+
# @raise [MdnQuery::NoEntryFound] if no entry was found
|
46
|
+
# @return [MdnQuery::Document] the document of entry
|
47
|
+
def self.first_match(query, options = {})
|
48
|
+
entry = list(query, options).first
|
49
|
+
entry.content
|
50
|
+
end
|
51
|
+
|
52
|
+
# Searches the given query and opens the result in the default browser.
|
53
|
+
#
|
54
|
+
# @param query [String] the query to search for
|
55
|
+
# @param options [Hash] additional query options (see
|
56
|
+
# {MdnQuery::Search#initialize})
|
57
|
+
# @raise [MdnQuery::HttpRequestFailed] if a HTTP request fails
|
58
|
+
# @raise [MdnQuery::NoEntryFound] if no entry was found
|
59
|
+
# @return [void]
|
60
|
+
def self.open_list(query, options = {})
|
61
|
+
search = MdnQuery::Search.new(query, options)
|
62
|
+
search.open
|
63
|
+
end
|
64
|
+
|
65
|
+
# Searches the given query and opens the first entry in the default browser.
|
66
|
+
#
|
67
|
+
# @param query [String] the query to search for
|
68
|
+
# @param options [Hash] additional query options (see
|
69
|
+
# {MdnQuery::Search#initialize})
|
70
|
+
# @raise [MdnQuery::HttpRequestFailed] if a HTTP request fails
|
71
|
+
# @raise [MdnQuery::NoEntryFound] if no entry was found
|
72
|
+
# @return [void]
|
73
|
+
def self.open_first_match(query, options = {})
|
74
|
+
entry = list(query, options).first
|
75
|
+
entry.open
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module MdnQuery
|
2
|
+
# A document of an entry of the Mozilla Developer Network documentation.
|
3
|
+
class Document
|
4
|
+
# @return [String]
|
5
|
+
attr_reader :title, :url
|
6
|
+
|
7
|
+
# @return [MdnQuery::Section] the top level section
|
8
|
+
attr_reader :section
|
9
|
+
|
10
|
+
# Creates a new document with an initial top level section.
|
11
|
+
#
|
12
|
+
# @param title [String] the titel of the top level section
|
13
|
+
# @param url [String] the URL to the document on the web
|
14
|
+
# @return [MdnQuery::Document]
|
15
|
+
def initialize(title, url = nil)
|
16
|
+
@title = title
|
17
|
+
@url = url
|
18
|
+
@section = MdnQuery::Section.new(title)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Opens the document in the default web browser if a URL has been specified.
|
22
|
+
#
|
23
|
+
# @return [void]
|
24
|
+
def open
|
25
|
+
Launchy.open(@url) unless @url.nil?
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns the string representation of the document.
|
29
|
+
#
|
30
|
+
# @return [String]
|
31
|
+
def to_s
|
32
|
+
@section.to_s
|
33
|
+
end
|
34
|
+
alias to_md to_s
|
35
|
+
end
|
36
|
+
end
|