mdn_query 0.1.0

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