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.
@@ -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
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
@@ -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
@@ -0,0 +1,16 @@
1
+ sudo: false
2
+ language: ruby
3
+ os:
4
+ - linux
5
+ - osx
6
+ cache:
7
+ bundler: true
8
+ rvm:
9
+ - 2.3.1
10
+ - ruby-head
11
+ matrix:
12
+ allow_failures:
13
+ - rvm: ruby-head
14
+ fast_finish: true
15
+ notifications:
16
+ email: false
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in mdn_query.gemspec
4
+ gemspec
@@ -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.
@@ -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
@@ -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]
@@ -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
@@ -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