pincerna 1.1.3
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 +7 -0
- data/.rubocop.yml +77 -0
- data/.travis-gemfile +17 -0
- data/.travis.yml +7 -0
- data/.yardopts +1 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +23 -0
- data/LICENSE.md +21 -0
- data/README.md +211 -0
- data/Rakefile +45 -0
- data/bin/pincernad +56 -0
- data/docs/Pincerna.html +130 -0
- data/docs/Pincerna/Base.html +3051 -0
- data/docs/Pincerna/Bookmark.html +523 -0
- data/docs/Pincerna/Cache.html +767 -0
- data/docs/Pincerna/ChromeBookmark.html +308 -0
- data/docs/Pincerna/CurrencyConversion.html +589 -0
- data/docs/Pincerna/FirefoxBookmark.html +328 -0
- data/docs/Pincerna/Ip.html +1017 -0
- data/docs/Pincerna/Map.html +399 -0
- data/docs/Pincerna/SafariBookmark.html +308 -0
- data/docs/Pincerna/Server.html +673 -0
- data/docs/Pincerna/Translation.html +517 -0
- data/docs/Pincerna/UnitConversion.html +1042 -0
- data/docs/Pincerna/Version.html +189 -0
- data/docs/Pincerna/Vpn.html +561 -0
- data/docs/Pincerna/Weather.html +837 -0
- data/docs/_index.html +298 -0
- data/docs/class_list.html +54 -0
- data/docs/css/common.css +1 -0
- data/docs/css/full_list.css +57 -0
- data/docs/css/style.css +338 -0
- data/docs/file.README.html +327 -0
- data/docs/file_list.html +56 -0
- data/docs/frames.html +28 -0
- data/docs/index.html +327 -0
- data/docs/js/app.js +214 -0
- data/docs/js/full_list.js +178 -0
- data/docs/js/jquery.js +4 -0
- data/docs/method_list.html +389 -0
- data/docs/top-level-namespace.html +112 -0
- data/icon.png +0 -0
- data/images/chrome.png +0 -0
- data/images/currency.png +0 -0
- data/images/firefox.png +0 -0
- data/images/map.png +0 -0
- data/images/network.png +0 -0
- data/images/safari.png +0 -0
- data/images/translate.png +0 -0
- data/images/unit.png +0 -0
- data/images/vpn.png +0 -0
- data/images/weather.png +0 -0
- data/info.plist +961 -0
- data/it.cowtech.pincernad.plist +19 -0
- data/lib/pincerna.rb +30 -0
- data/lib/pincerna/base.rb +258 -0
- data/lib/pincerna/bookmark.rb +80 -0
- data/lib/pincerna/cache.rb +61 -0
- data/lib/pincerna/chrome_bookmark.rb +40 -0
- data/lib/pincerna/currency_conversion.rb +134 -0
- data/lib/pincerna/firefox_bookmark.rb +92 -0
- data/lib/pincerna/ip.rb +135 -0
- data/lib/pincerna/map.rb +30 -0
- data/lib/pincerna/safari_bookmark.rb +40 -0
- data/lib/pincerna/server.rb +85 -0
- data/lib/pincerna/translation.rb +67 -0
- data/lib/pincerna/unit_conversion.rb +120 -0
- data/lib/pincerna/version.rb +24 -0
- data/lib/pincerna/vpn.rb +74 -0
- data/lib/pincerna/weather.rb +188 -0
- data/pincerna.alfredworkflow +0 -0
- data/pincerna.gemspec +36 -0
- data/pincerna.sh +9 -0
- data/spec/cassettes/Pincerna_CurrencyConversion/_perform_filtering/should_return_valid_values.yml +38 -0
- data/spec/cassettes/Pincerna_Ip/_get_local_addresses/should_return_a_list_of_addresses.yml +47 -0
- data/spec/cassettes/Pincerna_Ip/_get_public_address/should_return_public_IP_address.yml +44 -0
- data/spec/cassettes/Pincerna_Translation/_perform_filtering/should_default_from_English_to_the_given_language_when_only_one_is_present.yml +124 -0
- data/spec/cassettes/Pincerna_Translation/_perform_filtering/should_query_Google_Translate_for_sentences_returning_no_alternatives.yml +51 -0
- data/spec/cassettes/Pincerna_Translation/_perform_filtering/should_query_Google_Translate_for_single_words.yml +71 -0
- data/spec/cassettes/Pincerna_Weather/_get_forecast/should_append_name.yml +177 -0
- data/spec/cassettes/Pincerna_Weather/_get_forecast/should_get_correct_forecasts.yml +339 -0
- data/spec/cassettes/Pincerna_Weather/_lookup_places/should_return_an_existing_WOEID_without_making_any_request.yml +56 -0
- data/spec/cassettes/Pincerna_Weather/_lookup_places/should_search_for_places.yml +189 -0
- data/spec/cassettes/Pincerna_Weather/_perform_filtering/should_get_forecast.yml +56 -0
- data/spec/coverage_helper.rb +44 -0
- data/spec/pincerna/base_spec.rb +166 -0
- data/spec/pincerna/bookmark_spec.rb +65 -0
- data/spec/pincerna/cache_spec.rb +88 -0
- data/spec/pincerna/chrome_bookmark_spec.rb +114 -0
- data/spec/pincerna/currency_conversion_spec.rb +46 -0
- data/spec/pincerna/firefox_bookmark_spec.rb +46 -0
- data/spec/pincerna/ip_spec.rb +194 -0
- data/spec/pincerna/map_spec.rb +24 -0
- data/spec/pincerna/safari_bookmark_spec.rb +237 -0
- data/spec/pincerna/server_spec.rb +108 -0
- data/spec/pincerna/translation_spec.rb +55 -0
- data/spec/pincerna/unit_conversion_spec.rb +98 -0
- data/spec/pincerna/vpn_spec.rb +68 -0
- data/spec/pincerna/weather_spec.rb +131 -0
- data/spec/spec_helper.rb +48 -0
- metadata +283 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
#
|
|
3
|
+
# This file is part of the pincerna gem. Copyright (C) 2013 and above Shogun <shogun@cowtech.it>.
|
|
4
|
+
# Licensed under the MIT license, which can be found at https://choosealicense.com/licenses/mit.
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
module Pincerna
|
|
8
|
+
# Show the list of Chrome bookmarks.
|
|
9
|
+
class ChromeBookmark < Bookmark
|
|
10
|
+
# The icon to show for each feedback item.
|
|
11
|
+
ICON = Pincerna::Base::ROOT + "/images/chrome.png"
|
|
12
|
+
|
|
13
|
+
# The location of the bookmarks data
|
|
14
|
+
BOOKMARKS_DATA = File.expand_path("~/Library/Application Support/Google/Chrome/Default/Bookmarks")
|
|
15
|
+
|
|
16
|
+
# Reads the list of Chrome Bookmarks.
|
|
17
|
+
def read_bookmarks
|
|
18
|
+
data = File.read(BOOKMARKS_DATA) rescue nil
|
|
19
|
+
|
|
20
|
+
if data then
|
|
21
|
+
Oj.load(data)["roots"].each do |_, root|
|
|
22
|
+
scan_folder(root, "") if root.is_a?(Hash)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
# Scans a folder of bookmarks.
|
|
29
|
+
#
|
|
30
|
+
# @param node [Hash] The directory to visit.
|
|
31
|
+
# @param path [String] The path of this node.
|
|
32
|
+
def scan_folder(node, path)
|
|
33
|
+
path += " #{SEPARATOR} #{node["name"]}"
|
|
34
|
+
|
|
35
|
+
node["children"].each do |children|
|
|
36
|
+
children["type"] == "url" ? add_bookmark(children["name"], children["url"], path) : scan_folder(children, path)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
#
|
|
3
|
+
# This file is part of the pincerna gem. Copyright (C) 2013 and above Shogun <shogun@cowtech.it>.
|
|
4
|
+
# Licensed under the MIT license, which can be found at https://choosealicense.com/licenses/mit.
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
module Pincerna
|
|
8
|
+
# Converts a value from a currency to another.
|
|
9
|
+
class CurrencyConversion < Base
|
|
10
|
+
# The expression to match.
|
|
11
|
+
MATCHER = /^
|
|
12
|
+
(?<value>([+-]?)(\d+)([.,]\d+)?)
|
|
13
|
+
\s
|
|
14
|
+
(?<from>\S{1,3})
|
|
15
|
+
\s+
|
|
16
|
+
(to\s+)?
|
|
17
|
+
(?<to>\S{1,3})
|
|
18
|
+
(?<rate>\swith\srate)?
|
|
19
|
+
$/mix
|
|
20
|
+
|
|
21
|
+
# Relevant groups in the match.
|
|
22
|
+
RELEVANT_MATCHES = {
|
|
23
|
+
"value" => ->(context, value){ context.round_float(value.gsub(",", ".").to_f) },
|
|
24
|
+
"from" => ->(_, value) { value.upcase },
|
|
25
|
+
"to" => ->(_, value) { value.upcase },
|
|
26
|
+
"rate" => ->(_, value) { !value.nil? } # If show conversion rate
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
# The icon to show for each feedback item.
|
|
30
|
+
ICON = Pincerna::Base::ROOT + "/images/currency.png"
|
|
31
|
+
|
|
32
|
+
# The URL of the webservice.
|
|
33
|
+
URL = "http://rate-exchange.appspot.com/currency"
|
|
34
|
+
|
|
35
|
+
# A list of symbols and their associated ISO codes
|
|
36
|
+
SYMBOLS = {
|
|
37
|
+
"Lek" => "ALL",
|
|
38
|
+
"؋" => "AFN",
|
|
39
|
+
"$" => "USD",
|
|
40
|
+
"ƒ" => "ANG",
|
|
41
|
+
"ман" => "AZN",
|
|
42
|
+
"p." => "BYR",
|
|
43
|
+
"BZ$" => "BZD",
|
|
44
|
+
"$b" => "BOB",
|
|
45
|
+
"KM" => "BAM",
|
|
46
|
+
"P" => "BWP",
|
|
47
|
+
"лв" => "UZS",
|
|
48
|
+
"R$" => "BRL",
|
|
49
|
+
"៛" => "KHR",
|
|
50
|
+
"¥" => "JPY",
|
|
51
|
+
"₡" => "CRC",
|
|
52
|
+
"kn" => "HRK",
|
|
53
|
+
"₱" => "PHP",
|
|
54
|
+
"Kč" => "CZK",
|
|
55
|
+
"kr" => "SEK",
|
|
56
|
+
"RD$" => "DOP",
|
|
57
|
+
"£" => "GBP",
|
|
58
|
+
"€" => "EUR",
|
|
59
|
+
"¢" => "GHC",
|
|
60
|
+
"Q" => "GTQ",
|
|
61
|
+
"L" => "HNL",
|
|
62
|
+
"Ft" => "HUF",
|
|
63
|
+
"" => "TRY",
|
|
64
|
+
"Rp" => "IDR",
|
|
65
|
+
"﷼" => "YER",
|
|
66
|
+
"₪" => "ILS",
|
|
67
|
+
"J$" => "JMD",
|
|
68
|
+
"₩" => "KRW",
|
|
69
|
+
"₭" => "LAK",
|
|
70
|
+
"Ls" => "LVL",
|
|
71
|
+
"Lt" => "LTL",
|
|
72
|
+
"ден" => "MKD",
|
|
73
|
+
"RM" => "MYR",
|
|
74
|
+
"₨" => "LKR",
|
|
75
|
+
"₮" => "MNT",
|
|
76
|
+
"MT" => "MZN",
|
|
77
|
+
"C$" => "NIO",
|
|
78
|
+
"₦" => "NGN",
|
|
79
|
+
"B/." => "PAB",
|
|
80
|
+
"Gs" => "PYG",
|
|
81
|
+
"S/." => "PEN",
|
|
82
|
+
"zł" => "PLN",
|
|
83
|
+
"lei" => "RON",
|
|
84
|
+
"руб" => "RUB",
|
|
85
|
+
"Дин." => "RSD",
|
|
86
|
+
"S" => "SOS",
|
|
87
|
+
"R" => "ZAR",
|
|
88
|
+
"CHF" => "CHF",
|
|
89
|
+
"NT$" => "TWD",
|
|
90
|
+
"฿" => "THB",
|
|
91
|
+
"TT$" => "TTD",
|
|
92
|
+
"₤" => "TRL",
|
|
93
|
+
"₴" => "UAH",
|
|
94
|
+
"$U" => "UYU",
|
|
95
|
+
"Bs" => "VEF",
|
|
96
|
+
"₫" => "VND",
|
|
97
|
+
"Z$" => "ZWD"
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
# Converts a value from a currency to another.
|
|
101
|
+
#
|
|
102
|
+
# @param value [Float] The value to convert.
|
|
103
|
+
# @param from [String] The origin currency.
|
|
104
|
+
# @param to [String] The target currency.
|
|
105
|
+
# @param with_rate [Boolean] If to return the conversion rate in the results.
|
|
106
|
+
# @return [Hash|NilClass] The converted data or `nil` if the conversion failed.
|
|
107
|
+
def perform_filtering(value, from, to, with_rate)
|
|
108
|
+
from = replace_symbol(from)
|
|
109
|
+
to = replace_symbol(to)
|
|
110
|
+
response = fetch_remote_resource(URL, {q: value, from: from, to: to})
|
|
111
|
+
{value: value, from: from, to: to, result: round_float(response["v"]), rate: round_float(response["rate"]), with_rate: with_rate}
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Processes items to obtain feedback items.
|
|
115
|
+
#
|
|
116
|
+
# @param results [Hash] The item to process.
|
|
117
|
+
# @return [Array] The feedback items.
|
|
118
|
+
def process_results(results)
|
|
119
|
+
title = "%s %s = %s %s" % [format_float(results[:value]), results[:from], format_float(results[:result]), results[:to]]
|
|
120
|
+
title << " (1 %s = %s %s)" % [results[:from], format_float(results[:rate]), results[:to]] if results[:with_rate]
|
|
121
|
+
|
|
122
|
+
[{title: title, arg: format_float(results[:value]), subtitle: "Action this item to copy the converted amount on the clipboard.", icon: self.class::ICON}]
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
private
|
|
126
|
+
# Replaces a currency symbol with its corresponding ISO code.
|
|
127
|
+
#
|
|
128
|
+
# @param symbol [String] The symbol to replace.
|
|
129
|
+
# @return [String] The corresponding code. If none is found, the original symbol is returned.
|
|
130
|
+
def replace_symbol(symbol)
|
|
131
|
+
SYMBOLS.fetch(symbol, symbol)
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
#
|
|
3
|
+
# This file is part of the pincerna gem. Copyright (C) 2013 and above Shogun <shogun@cowtech.it>.
|
|
4
|
+
# Licensed under the MIT license, which can be found at https://choosealicense.com/licenses/mit.
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
module Pincerna
|
|
8
|
+
# Show the list of Firefox bookmarks.
|
|
9
|
+
class FirefoxBookmark < Bookmark
|
|
10
|
+
# The icon to show for each feedback item.
|
|
11
|
+
ICON = Pincerna::Base::ROOT + "/images/firefox.png"
|
|
12
|
+
|
|
13
|
+
# A wildcard to searc the default profile
|
|
14
|
+
PROFILES_SEARCH = File.expand_path("~/Library/Application Support/Firefox/Profiles/*.default")
|
|
15
|
+
|
|
16
|
+
# The queries to obtain the bookmarks
|
|
17
|
+
QUERIES = [
|
|
18
|
+
"SELECT b.title, p.url, b.parent FROM moz_bookmarks b, moz_places p WHERE b.type=1 AND b.fk=p.id",
|
|
19
|
+
"SELECT b.title, b.id, b.parent FROM moz_bookmarks b WHERE b.type=2"
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
# Reads the list of Firefox Bookmarks.
|
|
23
|
+
def read_bookmarks
|
|
24
|
+
path = Dir.glob(PROFILES_SEARCH).first
|
|
25
|
+
data = execute_command("/usr/bin/sqlite3", "-echo", "#{path}/places.sqlite", QUERIES.join("; "))
|
|
26
|
+
|
|
27
|
+
if data && !data.empty? then
|
|
28
|
+
@folders = {}
|
|
29
|
+
parse_bookmarks_data(data)
|
|
30
|
+
build_paths
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
# Parses bookmarks data.
|
|
36
|
+
#
|
|
37
|
+
# @param data [String] The data to parse.
|
|
38
|
+
def parse_bookmarks_data(data)
|
|
39
|
+
data = StringScanner.new(data)
|
|
40
|
+
data.skip_until(/\n/) # Discard the first line
|
|
41
|
+
|
|
42
|
+
# While we're still in the first query, look for bookmarks
|
|
43
|
+
while data.exist?(/#{QUERIES.last}/) do
|
|
44
|
+
line = data.scan_until(/\n/).strip
|
|
45
|
+
break if line == QUERIES.last
|
|
46
|
+
add_bookmark(*restrict_array(line.split("|"), 3))
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Now look for folder
|
|
50
|
+
while !data.eos? do
|
|
51
|
+
line = data.scan_until(/\n/).strip
|
|
52
|
+
add_folder(*restrict_array(line.split("|"), 3))
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Builds the paths of the bookmarks.
|
|
57
|
+
def build_paths
|
|
58
|
+
@bookmarks.map! do |bookmark|
|
|
59
|
+
bookmark[:path] = " #{SEPARATOR} #{build_path(bookmark[:path].to_i).reverse.join(" #{SEPARATOR} ")}"
|
|
60
|
+
bookmark
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Builds the full path of a folder.
|
|
65
|
+
#
|
|
66
|
+
# @param id [Fixnum] The id of the folder.
|
|
67
|
+
# @return [String] The path of the folder.
|
|
68
|
+
def build_path(id)
|
|
69
|
+
folder = @folders[id]
|
|
70
|
+
folder ? [folder[0]] + build_path(folder[1]).compact : []
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Adds a folder to the list.
|
|
74
|
+
#
|
|
75
|
+
# @param title [String] The name of the folder.
|
|
76
|
+
# @param id [String] The id of the folder.
|
|
77
|
+
# @param parent [String] The id of the parent folder.
|
|
78
|
+
def add_folder(title, id, parent)
|
|
79
|
+
@folders[id.to_i] = [title, parent.to_i] if !title.empty?
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Restrict array making sure it does not exceed a length.
|
|
83
|
+
#
|
|
84
|
+
# @param array [Array] The array to restrict.
|
|
85
|
+
# @param len [Fixnum] The maximum allowed length.
|
|
86
|
+
# @return [Array] The restricted array.
|
|
87
|
+
def restrict_array(array, len)
|
|
88
|
+
array[0] = "#{array.shift}|#{array[0]}" while array.length > len
|
|
89
|
+
array
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
data/lib/pincerna/ip.rb
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
#
|
|
3
|
+
# This file is part of the pincerna gem. Copyright (C) 2013 and above Shogun <shogun@cowtech.it>.
|
|
4
|
+
# Licensed under the MIT license, which can be found at https://choosealicense.com/licenses/mit.
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
module Pincerna
|
|
8
|
+
# Shows the IP addresses of all network interfaces.
|
|
9
|
+
class Ip < Base
|
|
10
|
+
# The expression to match.
|
|
11
|
+
MATCHER = /^(?<all>.*)$/i
|
|
12
|
+
|
|
13
|
+
# The icon to show for each feedback item.
|
|
14
|
+
ICON = Pincerna::Base::ROOT + "/images/network.png"
|
|
15
|
+
|
|
16
|
+
# The URL of the webservice.
|
|
17
|
+
URL = "http://api.externalip.net/ip"
|
|
18
|
+
|
|
19
|
+
# Shows the IP addresses of all network interfaces.
|
|
20
|
+
#
|
|
21
|
+
# @param query [Array] A query to match against interfaces names.
|
|
22
|
+
# @return [Array] A list of items to process.
|
|
23
|
+
def perform_filtering(query)
|
|
24
|
+
@interface_filter ||= query.empty? ? /.*/ : /#{query}/i
|
|
25
|
+
|
|
26
|
+
# Get local addresses
|
|
27
|
+
rv = get_local_addresses
|
|
28
|
+
|
|
29
|
+
# Sort interfaces and address, IPv4 first then IPv6
|
|
30
|
+
rv.sort! {|left, right|
|
|
31
|
+
cmp = left[:interface] <=> right[:interface] # Interface name first
|
|
32
|
+
cmp = compare_ip_classes(left[:address], right[:address]) if cmp == 0 # Now IPv4 first then IPv6
|
|
33
|
+
cmp = compare_ip_addresses(left[:address], right[:address]) if cmp == 0 # Finally addresses
|
|
34
|
+
cmp
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
# Add public address
|
|
38
|
+
rv = rv.insert(0, get_public_address) if @interface_filter.match("public")
|
|
39
|
+
|
|
40
|
+
rv
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Processes items to obtain feedback items.
|
|
44
|
+
#
|
|
45
|
+
# @param results [Array] The items to process.
|
|
46
|
+
# @return [Array] The feedback items.
|
|
47
|
+
def process_results(results)
|
|
48
|
+
results.map do |result|
|
|
49
|
+
title = "#{result[:interface] ? result[:interface] : "Public"} IP: #{result[:address]}"
|
|
50
|
+
{title: title, arg: result[:address], subtitle: "Action this item to copy the IP on the clipboard.", icon: ICON}
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Gets a list of local IP addresses.
|
|
55
|
+
#
|
|
56
|
+
# @return [Array] A list of IPs data.
|
|
57
|
+
def get_local_addresses
|
|
58
|
+
rv = []
|
|
59
|
+
names = get_interfaces_names
|
|
60
|
+
|
|
61
|
+
# Split by interfaces
|
|
62
|
+
interfaces = execute_command("/sbin/ifconfig").split(/(^\S+:\s+)/)
|
|
63
|
+
interfaces.shift # Discard first whitespace
|
|
64
|
+
|
|
65
|
+
# For each interface
|
|
66
|
+
interfaces.each_slice(2) do |interface, configuration|
|
|
67
|
+
# See if matches the query and then replace public name
|
|
68
|
+
interface = interface.gsub(/\s*(.+):\s*/, "\\1")
|
|
69
|
+
name = names[interface] ? "#{names[interface]} (#{interface})" : interface
|
|
70
|
+
next if !@interface_filter.match(name)
|
|
71
|
+
|
|
72
|
+
# Get addresses
|
|
73
|
+
addresses = StringScanner.new(configuration)
|
|
74
|
+
while addresses.scan_until(/inet(6?)\s/) do
|
|
75
|
+
rv << {interface: name, address: addresses.scan(/\S+/)}
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
rv
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Gets the public IP address for this machine.
|
|
83
|
+
#
|
|
84
|
+
# @return [Hash] The public IP address data.
|
|
85
|
+
def get_public_address
|
|
86
|
+
{interface: nil, address: fetch_remote_resource(URL, {}, false)}
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Compares two IP classes, giving higher priority to IPv4.
|
|
90
|
+
#
|
|
91
|
+
# @param left [String] The first IP to compare.
|
|
92
|
+
# @param right [String] The second IP to compare.
|
|
93
|
+
# @return [Fixnum] The result of the comparison.
|
|
94
|
+
def compare_ip_classes(left, right)
|
|
95
|
+
(left.index(":") ? 1 : 0) <=> (right.index(":") ? 1 : 0)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Compares to IP addresses, giving higher priority to local address such as 127.0.0.1.
|
|
99
|
+
#
|
|
100
|
+
# @param left [String] The first IP to compare.
|
|
101
|
+
# @param right [String] The second IP to compare.
|
|
102
|
+
# @return [Fixnum] The result of the comparison.
|
|
103
|
+
def compare_ip_addresses(left, right)
|
|
104
|
+
higher_priority = ["::1", "127.0.0.1", "10.0.0.1"]
|
|
105
|
+
cmp = (higher_priority.include?(left) ? 0 : 1) <=> (higher_priority.include?(right) ? 0 : 1)
|
|
106
|
+
cmp = left <=> right if cmp == 0
|
|
107
|
+
cmp
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Gets a hash with pair of interfaces and their human names.
|
|
111
|
+
#
|
|
112
|
+
# @return [Hash] The hash with interfaces' name.
|
|
113
|
+
def get_interfaces_names
|
|
114
|
+
rv = {"lo0" => "Loopback"}
|
|
115
|
+
|
|
116
|
+
names = execute_command("/usr/sbin/networksetup", "-listallhardwareports").split(/\n\n/)
|
|
117
|
+
names.shift # Discard first whitespace
|
|
118
|
+
|
|
119
|
+
names.each do |port|
|
|
120
|
+
port = StringScanner.new(port)
|
|
121
|
+
name = nil
|
|
122
|
+
interface = nil
|
|
123
|
+
|
|
124
|
+
if port.scan_until(/Hardware Port: /) then
|
|
125
|
+
name = port.scan_until(/\n/).strip
|
|
126
|
+
interface = port.scan_until(/\n/).strip if port.scan_until(/Device: /)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
rv[interface] = name if name && interface
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
rv
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
data/lib/pincerna/map.rb
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
#
|
|
3
|
+
# This file is part of the pincerna gem. Copyright (C) 2013 and above Shogun <shogun@cowtech.it>.
|
|
4
|
+
# Licensed under the MIT license, which can be found at https://choosealicense.com/licenses/mit.
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
module Pincerna
|
|
8
|
+
# Shows addresses or coordinates on Google Maps.
|
|
9
|
+
class Map < Base
|
|
10
|
+
# The icon to show for each feedback item.
|
|
11
|
+
ICON = Pincerna::Base::ROOT + "/images/map.png"
|
|
12
|
+
|
|
13
|
+
# Filters a query.
|
|
14
|
+
#
|
|
15
|
+
# @param query [String] An address to show on Google Maps.
|
|
16
|
+
# @return [Array] A list of items to process.
|
|
17
|
+
def perform_filtering(query)
|
|
18
|
+
{query: query}
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Processes items to obtain feedback items.
|
|
22
|
+
#
|
|
23
|
+
# @param results [Array] The items to process.
|
|
24
|
+
# @return [Array] The feedback items.
|
|
25
|
+
def process_results(results)
|
|
26
|
+
type = results[:query] =~ /((-?)\d+(\.\d+)?)\s*,\s*((-?)\d+(\.\d+)?)/ ? "coordinates" : "location"
|
|
27
|
+
[{title: "View #{type} on Google Maps", arg: CGI.escape(results[:query]), subtitle: "Action this item to open Google Maps in the browser.", icon: ICON}]
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
#
|
|
3
|
+
# This file is part of the pincerna gem. Copyright (C) 2013 and above Shogun <shogun@cowtech.it>.
|
|
4
|
+
# Licensed under the MIT license, which can be found at https://choosealicense.com/licenses/mit.
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
module Pincerna
|
|
8
|
+
# Show the list of Safari bookmarks.
|
|
9
|
+
class SafariBookmark < Bookmark
|
|
10
|
+
# The icon to show for each feedback item.
|
|
11
|
+
ICON = Pincerna::Base::ROOT + "/images/safari.png"
|
|
12
|
+
|
|
13
|
+
# The file with bookmarks data.
|
|
14
|
+
BOOKMARKS_DATA = File.expand_path("~/Library/Safari/Bookmarks.plist")
|
|
15
|
+
|
|
16
|
+
# Reads the list of Safari Bookmarks.
|
|
17
|
+
def read_bookmarks
|
|
18
|
+
data = execute_command("/usr/bin/plutil", "-convert", "xml1", "-o", "-", BOOKMARKS_DATA)
|
|
19
|
+
|
|
20
|
+
if data && !data.empty? then
|
|
21
|
+
Plist.parse_xml(data)["Children"].each do |children|
|
|
22
|
+
scan_folder(children, "")
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
# Scans a folder of bookmarks.
|
|
29
|
+
#
|
|
30
|
+
# @param node [Hash] The directory to visit.
|
|
31
|
+
# @param path [String] The path of this node.
|
|
32
|
+
def scan_folder(node, path)
|
|
33
|
+
path += " #{SEPARATOR} #{node["Title"]}"
|
|
34
|
+
|
|
35
|
+
(node["Children"] || []).each do |children|
|
|
36
|
+
children["WebBookmarkType"] == "WebBookmarkTypeLeaf" ? add_bookmark(children["URIDictionary"]["title"], children["URLString"], path) : scan_folder(children, path)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|