cani 0.1.2 → 0.2.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 +4 -4
- data/Gemfile.lock +3 -1
- data/cani.gemspec +2 -1
- data/exe/cani +1 -14
- data/lib/cani/api/browser.rb +21 -3
- data/lib/cani/api/feature/viewer.rb +293 -0
- data/lib/cani/api/feature.rb +17 -13
- data/lib/cani/api.rb +14 -9
- data/lib/cani/completions.rb +23 -12
- data/lib/cani/config.rb +111 -0
- data/lib/cani/fzf.rb +1 -1
- data/lib/cani/version.rb +1 -1
- data/lib/cani.rb +47 -11
- data/shell/completions/functions.bash +3 -0
- data/shell/completions/functions.zsh +3 -0
- metadata +28 -13
- data/lib/cani/api/config.rb +0 -121
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9de90bea20bfdaed9282223a8f2326c9a57515cba421460382388152613a92d5
|
4
|
+
data.tar.gz: a8dfeba0857de5d4e8a35e3971aa05feb3b1d60aca948d3383357074e449b581
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 63e0d0bf53d8e72915b0c5fe5f7997e7f3dd5341b973dc37c3180fe3b4a91c7f35370d43f57ccc717c24ad3d12a42b6a9bbb413de5afb2901ae0ed66b4c4678d
|
7
|
+
data.tar.gz: 514d3cf80000acd736d86f4bc5fdb991ed6d43a986cb6469760be5d92b4e1620ad4331fd34078906e17a3f1d16d17db11c52d2e4d63abba9560cee436b01d19b
|
data/Gemfile.lock
CHANGED
data/cani.gemspec
CHANGED
@@ -23,10 +23,11 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.require_paths = ['lib']
|
24
24
|
|
25
25
|
spec.add_runtime_dependency 'colorize'
|
26
|
+
spec.add_runtime_dependency 'curses'
|
26
27
|
spec.add_runtime_dependency 'json'
|
27
28
|
|
28
29
|
spec.add_development_dependency 'bundler', '~> 1.16'
|
29
|
-
spec.add_development_dependency 'rake', '~> 10.0'
|
30
30
|
spec.add_development_dependency 'pry'
|
31
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
31
32
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
32
33
|
end
|
data/exe/cani
CHANGED
@@ -4,17 +4,4 @@
|
|
4
4
|
require 'bundler/setup'
|
5
5
|
require 'cani'
|
6
6
|
|
7
|
-
|
8
|
-
# argument in ARGV.
|
9
|
-
cmd ||= Cani.api.config.args.first
|
10
|
-
|
11
|
-
# refresh all completions after new data has been fetched
|
12
|
-
Cani::Completions.install! if Cani.api.updated?
|
13
|
-
|
14
|
-
if cmd && Cani.respond_to?(cmd)
|
15
|
-
# if the command is recognized, execute it
|
16
|
-
Cani.send cmd
|
17
|
-
else
|
18
|
-
# otherwise, display help message
|
19
|
-
Cani.help
|
20
|
-
end
|
7
|
+
Cani.exec! ARGV[0], *ARGV[1..-1]
|
data/lib/cani/api/browser.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Cani
|
2
2
|
class Api
|
3
3
|
class Browser
|
4
|
-
attr_reader :name, :title, :prefix, :type, :versions, :usage, :abbr, :label
|
4
|
+
attr_reader :name, :title, :prefix, :type, :versions, :usage, :abbr, :label, :eras
|
5
5
|
|
6
6
|
ABBR_MAP = { 'ios' => 'saf.ios' }.freeze
|
7
7
|
LABEL_MAP = {
|
@@ -34,12 +34,30 @@ module Cani
|
|
34
34
|
@title = attributes['browser'].downcase
|
35
35
|
@prefix = attributes['prefix'].downcase
|
36
36
|
@type = attributes['type'].downcase
|
37
|
-
@usage = attributes['usage_global']
|
37
|
+
@usage = attributes['usage_global'].each_with_object({}) do |(v, u), h|
|
38
|
+
v.split('-').each { |ver| h[ver] = u }
|
39
|
+
end
|
40
|
+
@eras = attributes['versions'].each_with_object([]) do |v, a|
|
41
|
+
if v
|
42
|
+
v.split('-').each { |ver| a << ver }
|
43
|
+
else
|
44
|
+
a << v
|
45
|
+
end
|
46
|
+
end
|
38
47
|
@versions = @usage.keys
|
48
|
+
@features = {}
|
49
|
+
end
|
50
|
+
|
51
|
+
def most_popular_era_idx
|
52
|
+
eras.find_index usage.sort_by { |_, v| -v }.first.first
|
53
|
+
end
|
54
|
+
|
55
|
+
def max_column_width
|
56
|
+
[name.size, versions.map(&:size).max].max
|
39
57
|
end
|
40
58
|
|
41
59
|
def features_for(version)
|
42
|
-
@features ||= Cani.api.features.each_with_object({}) do |ft, h|
|
60
|
+
@features[version] ||= Cani.api.features.each_with_object({}) do |ft, h|
|
43
61
|
type = ft.support_in name, version
|
44
62
|
(h[type] ||= []) << { support: type, title: ft.title,
|
45
63
|
status: ft.status, percent: ft.percent }
|
@@ -0,0 +1,293 @@
|
|
1
|
+
module Cani
|
2
|
+
class Api
|
3
|
+
class Feature
|
4
|
+
class Viewer
|
5
|
+
attr_reader :width, :height, :feature, :browsers, :viewable, :col_width, :table_width
|
6
|
+
|
7
|
+
COLOR_PAIRS = {
|
8
|
+
# foreground colors
|
9
|
+
69 => [70, -1], # green on default (legend supported, feature status, percentage counter)
|
10
|
+
213 => [214, -1], # orange on default (legend partial, percentage counter)
|
11
|
+
195 => [9, -1], # red on default (legend unsupported, percentage counter)
|
12
|
+
133 => [128, -1], # magenta on default (legend flag, current feature status)
|
13
|
+
12 => [75, -1], # blue on default (legend prefix)
|
14
|
+
204 => [205, -1], # pink on default (legend polyfill)
|
15
|
+
99 => [8, -1], # gray on default (legend unknown)
|
16
|
+
|
17
|
+
|
18
|
+
# background colors
|
19
|
+
70 => [7, 70], # white on green (supported feature)
|
20
|
+
208 => [7, 214], # white on orange (partial feature)
|
21
|
+
196 => [7, 9], # white on red (unsupported feature)
|
22
|
+
134 => [7, 128], # white on magenta (flag features)
|
23
|
+
11 => [7, 75], # white on blue (prefix feature)
|
24
|
+
100 => [7, 8], # white on gray (unknown features)
|
25
|
+
205 => [7, 205], # white on pink (polyfill features)
|
26
|
+
|
27
|
+
# misc / one-off
|
28
|
+
254 => [238, 255], # black on light gray (browser names, legend title)
|
29
|
+
}.freeze
|
30
|
+
|
31
|
+
COLORS = {
|
32
|
+
# table headers
|
33
|
+
header: {fg: Curses.color_pair(254), bg: Curses.color_pair(254)},
|
34
|
+
|
35
|
+
# support types
|
36
|
+
default: {fg: Curses.color_pair(69), bg: Curses.color_pair(70)},
|
37
|
+
partial: {fg: Curses.color_pair(213), bg: Curses.color_pair(208)},
|
38
|
+
prefix: {fg: Curses.color_pair(12), bg: Curses.color_pair(11)},
|
39
|
+
polyfill: {fg: Curses.color_pair(204), bg: Curses.color_pair(205)},
|
40
|
+
flag: {fg: Curses.color_pair(133), bg: Curses.color_pair(134)},
|
41
|
+
unsupported: {fg: Curses.color_pair(195), bg: Curses.color_pair(196)},
|
42
|
+
unknown: {fg: Curses.color_pair(99), bg: Curses.color_pair(100)},
|
43
|
+
|
44
|
+
# statuses
|
45
|
+
un: {fg: Curses.color_pair(213), bg: Curses.color_pair(208)},
|
46
|
+
ot: {fg: Curses.color_pair(133), bg: Curses.color_pair(134)}
|
47
|
+
}.freeze
|
48
|
+
|
49
|
+
PERCENT_COLORS = {
|
50
|
+
70..101 => {fg: Curses.color_pair(69), bg: Curses.color_pair(70)},
|
51
|
+
40..70 => {fg: Curses.color_pair(213), bg: Curses.color_pair(208)},
|
52
|
+
0..40 => {fg: Curses.color_pair(195), bg: Curses.color_pair(196)}
|
53
|
+
}.freeze
|
54
|
+
|
55
|
+
ERAS = 6 # range of eras to show around current era (incl current)
|
56
|
+
COMPACT = 60 # column width at which to compress the layout
|
57
|
+
PADDING = 1 # horizontal cell padding
|
58
|
+
MARGIN = 1 # horizontal cell margin
|
59
|
+
|
60
|
+
def initialize(feature, browsers = Cani.api.browsers)
|
61
|
+
@feature = feature
|
62
|
+
@browsers = browsers
|
63
|
+
@viewable = browsers.size
|
64
|
+
|
65
|
+
resize
|
66
|
+
|
67
|
+
Curses.init_screen
|
68
|
+
Curses.curs_set 0
|
69
|
+
Curses.noecho
|
70
|
+
Curses.cbreak
|
71
|
+
|
72
|
+
if Curses.has_colors?
|
73
|
+
Curses.use_default_colors
|
74
|
+
Curses.start_color
|
75
|
+
end
|
76
|
+
|
77
|
+
COLOR_PAIRS.each do |(cn, clp)|
|
78
|
+
Curses.init_pair cn, *clp
|
79
|
+
end
|
80
|
+
|
81
|
+
trap('INT', &method(:close))
|
82
|
+
at_exit(&method(:close))
|
83
|
+
end
|
84
|
+
|
85
|
+
def close(*args)
|
86
|
+
Curses.close_screen
|
87
|
+
end
|
88
|
+
|
89
|
+
def draw
|
90
|
+
Curses.clear
|
91
|
+
|
92
|
+
percent_num = format '%.2f%%', feature.percent
|
93
|
+
status_format = "[#{feature.status}]"
|
94
|
+
percent_label = compact? ? '' : 'support: '
|
95
|
+
legend_format = 'legend'.center table_width
|
96
|
+
|
97
|
+
title_size = [table_width - percent_num.size - percent_label.size - status_format.size - 3, 1].max
|
98
|
+
title_size += status_format.size if compact?
|
99
|
+
title_chunks = feature.title.chars.each_slice(title_size).map { |chrs| chrs.compact.join }
|
100
|
+
|
101
|
+
type_count = Feature::TYPES.keys.size
|
102
|
+
offset_x = ((width - table_width) / 2.0).floor
|
103
|
+
offset_y = ((height - ERAS - title_chunks.size - 10 - (type_count / [type_count, viewable].min.to_f).ceil) / 2.0).floor
|
104
|
+
cy = 0
|
105
|
+
|
106
|
+
# positioning and drawing of percentage
|
107
|
+
perc_num_xs = table_width - percent_num.size
|
108
|
+
Curses.setpos offset_y + cy, offset_x + perc_num_xs
|
109
|
+
Curses.attron percent_color(feature.percent) do
|
110
|
+
Curses.addstr percent_num
|
111
|
+
end
|
112
|
+
|
113
|
+
# positioning and drawing of 'support: ' text
|
114
|
+
# ditch this part all together when in compact mode
|
115
|
+
unless compact?
|
116
|
+
perc_lbl_xs = perc_num_xs - percent_label.size
|
117
|
+
Curses.setpos offset_y + cy, offset_x + perc_lbl_xs
|
118
|
+
Curses.addstr percent_label
|
119
|
+
end
|
120
|
+
|
121
|
+
# draw possibly multi-line feature title
|
122
|
+
title_chunks.each do |part|
|
123
|
+
Curses.setpos offset_y + cy, offset_x
|
124
|
+
Curses.addstr part
|
125
|
+
|
126
|
+
cy += 1
|
127
|
+
end
|
128
|
+
|
129
|
+
# status positioning and drawing
|
130
|
+
# when compact? draw it on the second line instead of the first line at the end of the title
|
131
|
+
cy += 1
|
132
|
+
status_yp = offset_y + (compact? ? 1 : 0)
|
133
|
+
status_xp = offset_x + (compact? ? table_width - status_format.size
|
134
|
+
: [title_size, feature.title.size].min + 1)
|
135
|
+
|
136
|
+
Curses.setpos status_yp, status_xp
|
137
|
+
Curses.attron status_color(feature.status) do
|
138
|
+
Curses.addstr status_format
|
139
|
+
end
|
140
|
+
|
141
|
+
# meaty part, loop through browsers to create
|
142
|
+
# the final feature table
|
143
|
+
browsers[0...viewable].each.with_index do |browser, x|
|
144
|
+
# some set up to find the current era for each browser
|
145
|
+
# and creating a range around that to show past / coming support
|
146
|
+
era_idx = browser.most_popular_era_idx
|
147
|
+
era_range = (era_idx - (ERAS / 2.0).floor + 1)..(era_idx + (ERAS / 2.0).ceil)
|
148
|
+
bx = offset_x + x * col_width + x
|
149
|
+
by = offset_y + cy
|
150
|
+
|
151
|
+
# draw browser names
|
152
|
+
Curses.setpos by, bx
|
153
|
+
Curses.attron color(:header) do
|
154
|
+
Curses.addstr browser.name.tr('_', '.').center(col_width)
|
155
|
+
end
|
156
|
+
|
157
|
+
# accordingly increment current browser y for the table header (browser names)
|
158
|
+
# and an additional empty line below the table header
|
159
|
+
by += 2
|
160
|
+
|
161
|
+
# draw era's for the current browser
|
162
|
+
era_range.each.with_index do |cur_era, y|
|
163
|
+
era = browser.eras[cur_era].to_s
|
164
|
+
colr = color(feature.support_in(browser.name, era))
|
165
|
+
|
166
|
+
# since the current era versions are displayed as 3-line rows
|
167
|
+
# with an empty line before and after them, when we are at the current
|
168
|
+
# era we increment era y by an additional 2 for the lines above,
|
169
|
+
# whenever we are past the current era, increment by 2 for above plus 2
|
170
|
+
# extra lines below the current era
|
171
|
+
ey = by + y + (cur_era == era_idx ? 2 : (cur_era > era_idx ? 4 : 0))
|
172
|
+
|
173
|
+
# only show relevant browsers
|
174
|
+
if browser.usage[era].to_i >= 0.5 || (!era.empty? && cur_era >= era_idx)
|
175
|
+
Curses.setpos ey, bx
|
176
|
+
Curses.attron colr do
|
177
|
+
Curses.addstr era.center(col_width)
|
178
|
+
end
|
179
|
+
|
180
|
+
# previously, we only skipped some lines in order to create
|
181
|
+
# enough space to create the 3-line current era
|
182
|
+
# this snippet fills the line before and after the current era
|
183
|
+
# with the same color that the era has for that browser / feature
|
184
|
+
if cur_era == era_idx
|
185
|
+
[-1, 1].each do |relative_y|
|
186
|
+
Curses.setpos ey - relative_y, bx
|
187
|
+
Curses.attron colr do
|
188
|
+
Curses.addstr ' ' * col_width
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
# increment current y by amount of eras
|
197
|
+
# plus the 4 lines around the current era
|
198
|
+
# plus the 1 line of browser names
|
199
|
+
# plus the 2 blank lines above and below the eras
|
200
|
+
cy += ERAS + 7
|
201
|
+
|
202
|
+
# print legend header
|
203
|
+
Curses.setpos offset_y + cy, offset_x
|
204
|
+
Curses.attron color(:header) do
|
205
|
+
Curses.addstr legend_format
|
206
|
+
end
|
207
|
+
|
208
|
+
# increment current y by 2
|
209
|
+
# one for the header line
|
210
|
+
# plus one for a blank line below it
|
211
|
+
cy += 2
|
212
|
+
|
213
|
+
# loop through all features to create a legend
|
214
|
+
# showing which label belongs to which color
|
215
|
+
Feature::TYPES.values.each_slice viewable do |group|
|
216
|
+
group.compact.each.with_index do |type, lx|
|
217
|
+
Curses.setpos offset_y + cy, offset_x + lx * col_width + lx
|
218
|
+
Curses.attron color(type[:name], :fg) do
|
219
|
+
Curses.addstr "#{type[:short]}(#{type[:symbol]})".center(col_width)
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
# if there is more than one group, print the next
|
224
|
+
# group on a new line
|
225
|
+
cy += 1
|
226
|
+
end
|
227
|
+
|
228
|
+
Curses.refresh
|
229
|
+
end
|
230
|
+
|
231
|
+
def render
|
232
|
+
loop do
|
233
|
+
Curses.clear
|
234
|
+
draw
|
235
|
+
|
236
|
+
key = Curses.getch
|
237
|
+
case key
|
238
|
+
when Curses::KEY_RESIZE then resize
|
239
|
+
else break unless key.nil?
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
close
|
244
|
+
end
|
245
|
+
|
246
|
+
def colw
|
247
|
+
colw = PADDING * 2 + browsers[0..viewable].map(&:max_column_width).max
|
248
|
+
|
249
|
+
colw.even? ? colw : colw + 1
|
250
|
+
end
|
251
|
+
|
252
|
+
def tablew
|
253
|
+
colw * viewable + viewable - 1
|
254
|
+
end
|
255
|
+
|
256
|
+
def resize
|
257
|
+
@height, @width = IO.console.winsize
|
258
|
+
@viewable = browsers.size
|
259
|
+
|
260
|
+
while tablew > @width
|
261
|
+
@viewable -= 1
|
262
|
+
end
|
263
|
+
|
264
|
+
@col_width = [colw, Feature::TYPES.map { |(_, h)| h[:short].size }.max + 3].max
|
265
|
+
@table_width = tablew
|
266
|
+
end
|
267
|
+
|
268
|
+
def compact?
|
269
|
+
width < COMPACT
|
270
|
+
end
|
271
|
+
|
272
|
+
def color(key, type = :bg)
|
273
|
+
target = key.to_s.downcase.to_sym
|
274
|
+
type = type.to_sym
|
275
|
+
|
276
|
+
COLORS.find { |(k, _)| k == target }.to_a
|
277
|
+
.fetch(1, {})
|
278
|
+
.fetch(type, COLORS[:default][type])
|
279
|
+
end
|
280
|
+
|
281
|
+
def status_color(status)
|
282
|
+
color status, :fg
|
283
|
+
end
|
284
|
+
|
285
|
+
def percent_color(percent)
|
286
|
+
PERCENT_COLORS.find { |(r, _)| r.include? percent }.to_a
|
287
|
+
.fetch(1, {})
|
288
|
+
.fetch(:fg, COLORS[:unknown][:fg])
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
data/lib/cani/api/feature.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Cani
|
2
2
|
class Api
|
3
3
|
class Feature
|
4
|
-
attr_reader :title, :status, :spec, :stats, :percent
|
4
|
+
attr_reader :title, :status, :spec, :stats, :percent, :name
|
5
5
|
|
6
6
|
STATUSES = {
|
7
7
|
'rec' => 'rc',
|
@@ -10,38 +10,42 @@ module Cani
|
|
10
10
|
}.freeze
|
11
11
|
|
12
12
|
TYPES = {
|
13
|
-
'y' => {symbol: '+', name: :default, short: :
|
14
|
-
'a' => {symbol: '~', name: :partial, short: :
|
15
|
-
'n' => {symbol: '-', name: :unsupported, short: :
|
16
|
-
'p' => {symbol: '#', name: :polyfill, short: :
|
17
|
-
'x' => {symbol: '@', name: :prefix, short: :
|
18
|
-
'd' => {symbol: '!', name: :flag, short: :
|
19
|
-
'u' => {symbol: '?', name: :unknown, short: :
|
13
|
+
'y' => {symbol: '+', name: :default, short: :sup},
|
14
|
+
'a' => {symbol: '~', name: :partial, short: :prt},
|
15
|
+
'n' => {symbol: '-', name: :unsupported, short: :not},
|
16
|
+
'p' => {symbol: '#', name: :polyfill, short: :ply},
|
17
|
+
'x' => {symbol: '@', name: :prefix, short: :pfx},
|
18
|
+
'd' => {symbol: '!', name: :flag, short: :flg},
|
19
|
+
'u' => {symbol: '?', name: :unknown, short: :unk}
|
20
20
|
}.freeze
|
21
21
|
|
22
22
|
def initialize(attributes = {})
|
23
|
+
@name = attributes[:name].to_s.downcase
|
23
24
|
@title = attributes['title']
|
24
25
|
@status = STATUSES.fetch attributes['status'], attributes['status']
|
25
26
|
@spec = attributes['spec']
|
26
27
|
@percent = attributes['usage_perc_y']
|
27
28
|
@stats = attributes['stats'].each_with_object({}) do |(k, v), h|
|
28
|
-
h[k] = v.
|
29
|
+
h[k] = v.each_with_object({}) do |(vv, s), hh|
|
30
|
+
vv.split('-').each { |ver| hh[ver] = s[0] }
|
31
|
+
end
|
29
32
|
end
|
30
33
|
end
|
31
34
|
|
32
35
|
def current_support
|
33
|
-
@current_support ||= Cani.
|
36
|
+
@current_support ||= Cani.config.browsers.map do |browser|
|
34
37
|
bridx = Cani.api.browsers.find_index { |brs| brs.name == browser }
|
35
38
|
brwsr = Cani.api.browsers[bridx] unless bridx.nil?
|
36
|
-
syms = stats[browser].values.
|
37
|
-
.
|
39
|
+
syms = stats[browser].values.compact.last(Cani.config.versions)
|
40
|
+
.map { |s| TYPES[s][:symbol] || '' }
|
41
|
+
.join.rjust Cani.config.versions
|
38
42
|
|
39
43
|
syms + brwsr.abbr
|
40
44
|
end
|
41
45
|
end
|
42
46
|
|
43
47
|
def support_in(browser, version)
|
44
|
-
TYPES.fetch(stats[browser.to_s][version.to_s], {})
|
48
|
+
TYPES.fetch(stats[browser.to_s][version.to_s.downcase], {})
|
45
49
|
.fetch :name, :unknown
|
46
50
|
end
|
47
51
|
|
data/lib/cani/api.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
require 'net/http'
|
2
2
|
|
3
|
-
require_relative 'api/config'
|
4
3
|
require_relative 'api/browser'
|
5
4
|
require_relative 'api/feature'
|
5
|
+
require_relative 'api/feature/viewer'
|
6
6
|
|
7
7
|
module Cani
|
8
8
|
class Api
|
@@ -12,9 +12,9 @@ module Cani
|
|
12
12
|
|
13
13
|
def load_data(fetch: false)
|
14
14
|
@upd = false
|
15
|
-
data_file = File.join config.directory, 'caniuse.json'
|
15
|
+
data_file = File.join Cani.config.directory, 'caniuse.json'
|
16
16
|
data_exists = File.exist? data_file
|
17
|
-
data_up_to_date = data_exists ? (Time.now.to_i - File.mtime(data_file).to_i < config.expire.to_i)
|
17
|
+
data_up_to_date = data_exists ? (Time.now.to_i - File.mtime(data_file).to_i < Cani.config.expire.to_i)
|
18
18
|
: false
|
19
19
|
|
20
20
|
if !fetch && data_exists && data_up_to_date
|
@@ -40,7 +40,7 @@ module Cani
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def remove!
|
43
|
-
data_file = File.join config.directory, 'caniuse.json'
|
43
|
+
data_file = File.join Cani.config.directory, 'caniuse.json'
|
44
44
|
|
45
45
|
File.unlink data_file if File.exist? data_file
|
46
46
|
end
|
@@ -53,14 +53,19 @@ module Cani
|
|
53
53
|
@upd
|
54
54
|
end
|
55
55
|
|
56
|
-
def
|
57
|
-
|
56
|
+
def find_feature(name)
|
57
|
+
name = Regexp.new name.to_s.downcase.gsub(/(\W)/, '.*')
|
58
|
+
idx = features.find_index do |ft|
|
59
|
+
ft.title.downcase.match?(name) || ft.name.downcase.match?(name)
|
60
|
+
end
|
61
|
+
|
62
|
+
features[idx] if idx
|
58
63
|
end
|
59
64
|
|
60
65
|
def find_browser(name)
|
61
66
|
name = name.to_s.downcase
|
62
67
|
idx = browsers.find_index do |bwsr|
|
63
|
-
[bwsr.title, bwsr.name, bwsr.abbr].include? name
|
68
|
+
[bwsr.title, bwsr.name, bwsr.abbr].map(&:downcase).include? name
|
64
69
|
end
|
65
70
|
|
66
71
|
browsers[idx] if idx
|
@@ -73,12 +78,12 @@ module Cani
|
|
73
78
|
end
|
74
79
|
|
75
80
|
def features
|
76
|
-
@features ||= @data['data'].
|
81
|
+
@features ||= @data['data'].map { |(name, info)| Feature.new info.merge(name: name) }
|
77
82
|
end
|
78
83
|
|
79
84
|
def raw
|
80
85
|
begin
|
81
|
-
Net::HTTP.get URI(config.source)
|
86
|
+
Net::HTTP.get URI(Cani.config.source)
|
82
87
|
rescue
|
83
88
|
nil
|
84
89
|
end
|
data/lib/cani/completions.rb
CHANGED
@@ -3,12 +3,21 @@ module Cani
|
|
3
3
|
def self.generate_fish
|
4
4
|
gem_root = File.join File.dirname(__FILE__), '../../'
|
5
5
|
tpl = File.read File.join(gem_root, 'shell/completions/functions.fish')
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
|
7
|
+
shw = Cani.api.browsers.reduce String.new do |acc, browser|
|
8
|
+
versions = browser.versions.reverse.join(' ')
|
9
|
+
acc +
|
10
|
+
"\ncomplete -f -c cani -n '__fish_cani_using_command show' -a '#{browser.abbr}' -d '#{browser.label}'" +
|
11
|
+
"\ncomplete -f -c cani -n '__fish_cani_showing_browser #{browser.abbr}' -a '#{versions}'"
|
12
|
+
end
|
13
|
+
|
14
|
+
use = Cani.api.features.reduce String.new do |acc, feature|
|
15
|
+
description = feature.title.size > 40 ? feature.title[0..28] + '..' : feature.title
|
16
|
+
acc +
|
17
|
+
"\ncomplete -f -c cani -n '__fish_cani_using_command use' -a '#{feature.name}' -d '#{description}'"
|
9
18
|
end
|
10
19
|
|
11
|
-
tpl + shw
|
20
|
+
tpl + shw + "\n" + use
|
12
21
|
end
|
13
22
|
|
14
23
|
def self.generate_zsh
|
@@ -22,6 +31,7 @@ module Cani
|
|
22
31
|
end.strip
|
23
32
|
|
24
33
|
tpl.gsub('{{names}}', Cani.api.browsers.map(&:abbr).join(' '))
|
34
|
+
.gsub('{{features}}', Cani.api.features.map(&:name).join(' '))
|
25
35
|
.gsub '{{versions}}', versions
|
26
36
|
end
|
27
37
|
|
@@ -36,21 +46,22 @@ module Cani
|
|
36
46
|
end.strip
|
37
47
|
|
38
48
|
tpl.gsub('{{names}}', Cani.api.browsers.map(&:abbr).join(' '))
|
49
|
+
.gsub('{{features}}', Cani.api.features.map(&:name).join(' '))
|
39
50
|
.gsub '{{versions}}', versions
|
40
51
|
end
|
41
52
|
|
42
53
|
def self.install!
|
43
54
|
# create all parent folders
|
44
|
-
FileUtils.mkdir_p Cani.
|
45
|
-
FileUtils.mkdir_p Cani.
|
55
|
+
FileUtils.mkdir_p Cani.config.fish_comp_dir
|
56
|
+
FileUtils.mkdir_p Cani.config.comp_dir
|
46
57
|
|
47
58
|
# write each completion file
|
48
|
-
File.open File.join(Cani.
|
59
|
+
File.open File.join(Cani.config.fish_comp_dir, 'cani.fish'), 'w' do |file|
|
49
60
|
file << generate_fish
|
50
61
|
end
|
51
62
|
|
52
63
|
%w[bash zsh].each do |shell|
|
53
|
-
File.open File.join(Cani.
|
64
|
+
File.open File.join(Cani.config.comp_dir, "_cani.#{shell}"), 'w' do |file|
|
54
65
|
file << send("generate_#{shell}")
|
55
66
|
end
|
56
67
|
end
|
@@ -60,12 +71,12 @@ module Cani
|
|
60
71
|
end
|
61
72
|
|
62
73
|
def self.remove!
|
63
|
-
fish_comp = File.join Cani.
|
74
|
+
fish_comp = File.join Cani.config.fish_comp_dir, 'cani.fish'
|
64
75
|
|
65
76
|
File.unlink fish_comp if File.exist? fish_comp
|
66
77
|
|
67
78
|
%w[bash zsh].each do |shell|
|
68
|
-
shell_comp = File.join Cani.
|
79
|
+
shell_comp = File.join Cani.config.comp_dir, "_cani.#{shell}"
|
69
80
|
|
70
81
|
File.unlink shell_comp if File.exist? shell_comp
|
71
82
|
end
|
@@ -78,7 +89,7 @@ module Cani
|
|
78
89
|
%w[bash zsh].each do |shell|
|
79
90
|
shellrc = File.join Dir.home, ".#{shell}rc"
|
80
91
|
lines = File.read(shellrc).split "\n"
|
81
|
-
comp_path = File.join Cani.
|
92
|
+
comp_path = File.join Cani.config.comp_dir, "_cani.#{shell}"
|
82
93
|
rm_idx = lines.find_index { |l| l.match? comp_path }
|
83
94
|
|
84
95
|
lines.delete_at rm_idx unless rm_idx.nil?
|
@@ -90,7 +101,7 @@ module Cani
|
|
90
101
|
%w[bash zsh].each do |shell|
|
91
102
|
shellrc = File.join Dir.home, ".#{shell}rc"
|
92
103
|
lines = File.read(shellrc).split "\n"
|
93
|
-
comp_path = File.join Cani.
|
104
|
+
comp_path = File.join Cani.config.comp_dir, "_cani.#{shell}"
|
94
105
|
slidx = lines.find_index { |l| l.match? comp_path }
|
95
106
|
|
96
107
|
if slidx
|
data/lib/cani/config.rb
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
module Cani
|
2
|
+
class Config
|
3
|
+
attr_reader :settings
|
4
|
+
|
5
|
+
FILE = File.join(Dir.home, '.config', 'cani', 'config.yml').freeze
|
6
|
+
DIRECTORY = File.dirname(FILE).freeze
|
7
|
+
COMP_DIR = File.join(DIRECTORY, 'completions').freeze
|
8
|
+
FISH_DIR = File.join(Dir.home, '.config', 'fish').freeze
|
9
|
+
FISH_COMP_DIR = File.join(FISH_DIR, 'completions').freeze
|
10
|
+
DEFAULTS = {
|
11
|
+
# data settings
|
12
|
+
'expire' => 86_400,
|
13
|
+
'source' => 'https://raw.githubusercontent.com/Fyrd/caniuse/master/data.json',
|
14
|
+
|
15
|
+
# usage settings
|
16
|
+
'versions' => 1,
|
17
|
+
'browsers' => %w[ie edge chrome firefox safari ios_saf opera android bb]
|
18
|
+
}.freeze
|
19
|
+
|
20
|
+
def initialize(**opts)
|
21
|
+
@settings = DEFAULTS.merge opts
|
22
|
+
|
23
|
+
if File.exist? file
|
24
|
+
if (yml = YAML.load_file(file))
|
25
|
+
@settings.merge! yml
|
26
|
+
end
|
27
|
+
else
|
28
|
+
install!
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def file
|
33
|
+
FILE
|
34
|
+
end
|
35
|
+
|
36
|
+
def directory
|
37
|
+
DIRECTORY
|
38
|
+
end
|
39
|
+
|
40
|
+
def comp_dir
|
41
|
+
COMP_DIR
|
42
|
+
end
|
43
|
+
|
44
|
+
def fish_dir
|
45
|
+
FISH_DIR
|
46
|
+
end
|
47
|
+
|
48
|
+
def fish_comp_dir
|
49
|
+
FISH_COMP_DIR
|
50
|
+
end
|
51
|
+
|
52
|
+
def remove!
|
53
|
+
File.unlink file if File.exist? file
|
54
|
+
FileUtils.rm_rf directory if Dir.exist? directory
|
55
|
+
end
|
56
|
+
|
57
|
+
def install!
|
58
|
+
hrs = (DEFAULTS['expire'] / 3600.to_f).round 2
|
59
|
+
days = (hrs / 24.to_f).round 2
|
60
|
+
wk = (days / 7.to_f).round 2
|
61
|
+
mo = (days / 30.to_f).round 2
|
62
|
+
tstr = if mo >= 1
|
63
|
+
"#{mo == mo.to_i ? mo.to_i : mo} month#{mo != 1 ? 's' : ''}"
|
64
|
+
elsif wk >= 1
|
65
|
+
"#{wk == wk.to_i ? wk.to_i : wk} week#{wk != 1 ? 's' : ''}"
|
66
|
+
elsif days >= 1
|
67
|
+
"#{days == days.to_i ? days.to_i : days} day#{days != 1 ? 's' : ''}"
|
68
|
+
else
|
69
|
+
"#{hrs == hrs.to_i ? hrs.to_i : hrs} hour#{hrs != 1 ? 's' : ''}"
|
70
|
+
end
|
71
|
+
|
72
|
+
FileUtils.mkdir_p directory
|
73
|
+
File.open file, 'w' do |f|
|
74
|
+
f << "---\n"
|
75
|
+
f << "# this is the default configuration file for the \"Cani\" RubyGem.\n"
|
76
|
+
f << "# it contains some options to control what is shown, when new data\n"
|
77
|
+
f << "# is fetched, where it should be fetched from.\n"
|
78
|
+
f << "# documentation: https://github.com/sidofc/cani\n"
|
79
|
+
f << "# rubygems: https://rubygems.org/gems/cani\n\n"
|
80
|
+
f << "# the \"expire\" key defines the interval at which new data is\n"
|
81
|
+
f << "# fetched from \"source\". It's value is passed in as seconds\n"
|
82
|
+
f << "# default value: #{DEFAULTS['expire']} # => #{tstr}\n"
|
83
|
+
f << "expire: #{expire}\n\n"
|
84
|
+
f << "# the \"source\" key is used to fetch the data required for\n"
|
85
|
+
f << "# this command to work.\n"
|
86
|
+
f << "source: #{source}\n\n"
|
87
|
+
f << "# the \"versions\" key defines how many versions of support\n"
|
88
|
+
f << "# will be shown in the \"use\" command\n"
|
89
|
+
f << "# e.g. `-ie +edge` becomes `--ie ++edge` when this is set to 2, etc..."
|
90
|
+
f << "versions: #{versions}\n\n"
|
91
|
+
f << "# the \"browsers\" key defines which browsers are shown\n"
|
92
|
+
f << "# in the \"use\" command\n"
|
93
|
+
f << "browsers:\n"
|
94
|
+
f << " # enabled:\n"
|
95
|
+
f << browsers.map { |bn| " - #{bn}" }.join("\n") + "\n"
|
96
|
+
f << " # others:\n"
|
97
|
+
f << (Cani.api.browsers.map(&:name) - browsers).map { |bn| " # - #{bn}" }.join("\n")
|
98
|
+
end
|
99
|
+
|
100
|
+
Completions.install!
|
101
|
+
end
|
102
|
+
|
103
|
+
def method_missing(mtd, *args, &block)
|
104
|
+
settings.key?(mtd.to_s) ? settings[mtd.to_s] : super
|
105
|
+
end
|
106
|
+
|
107
|
+
def respond_to_missing?(mtd, include_private = false)
|
108
|
+
settings.key? mtd.to_s
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
data/lib/cani/fzf.rb
CHANGED
@@ -29,7 +29,7 @@ module Cani
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def self.feature_rows
|
32
|
-
Cani.api.features.map do |ft|
|
32
|
+
@feature_rows ||= Cani.api.features.map do |ft|
|
33
33
|
pc = format('%.2f%%', ft.percent).rjust 6
|
34
34
|
tt = format('%-24s', ft.title.size > 24 ? ft.title[0..23].strip + '..'
|
35
35
|
: ft.title)
|
data/lib/cani/version.rb
CHANGED
data/lib/cani.rb
CHANGED
@@ -1,12 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'io/console'
|
4
|
+
require 'curses'
|
3
5
|
require 'colorize'
|
4
6
|
require 'json'
|
5
7
|
require 'yaml'
|
6
8
|
|
7
|
-
require 'cani/version'
|
8
9
|
require 'cani/api'
|
9
10
|
require 'cani/fzf'
|
11
|
+
require 'cani/config'
|
12
|
+
require 'cani/version'
|
10
13
|
require 'cani/completions'
|
11
14
|
|
12
15
|
# Cani
|
@@ -15,6 +18,27 @@ module Cani
|
|
15
18
|
@api ||= Api.new
|
16
19
|
end
|
17
20
|
|
21
|
+
def self.config
|
22
|
+
@settings ||= Config.new
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
def self.exec!(command, *args)
|
27
|
+
command = :help unless command && respond_to?(command)
|
28
|
+
command = command.to_s.downcase.to_sym
|
29
|
+
|
30
|
+
case command
|
31
|
+
when :use
|
32
|
+
use args[0]
|
33
|
+
when :show
|
34
|
+
show args[0], args[1]
|
35
|
+
when :update, :purge, :help, :version, :install_completions
|
36
|
+
send command
|
37
|
+
else
|
38
|
+
help
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
18
42
|
def self.help
|
19
43
|
puts "Cani #{VERSION} <https://github.com/SidOfc/cani>"
|
20
44
|
puts ''
|
@@ -57,7 +81,7 @@ module Cani
|
|
57
81
|
def self.purge
|
58
82
|
Completions.remove!
|
59
83
|
api.remove!
|
60
|
-
|
84
|
+
config.remove!
|
61
85
|
end
|
62
86
|
|
63
87
|
def self.update
|
@@ -65,16 +89,28 @@ module Cani
|
|
65
89
|
end
|
66
90
|
|
67
91
|
def self.edit
|
68
|
-
system ENV.fetch('EDITOR', 'vim'),
|
92
|
+
system ENV.fetch('EDITOR', 'vim'), config.file
|
69
93
|
end
|
70
94
|
|
71
|
-
def self.use
|
72
|
-
|
73
|
-
|
74
|
-
|
95
|
+
def self.use(feature = nil)
|
96
|
+
if feature && (feature = api.find_feature(feature))
|
97
|
+
Api::Feature::Viewer.new(feature).render
|
98
|
+
use
|
99
|
+
elsif (chosen = Fzf.pick(Fzf.feature_rows,
|
100
|
+
header: 'use] [' + Api::Feature.support_legend,
|
101
|
+
colors: %i[green light_black light_white light_black]))
|
102
|
+
|
103
|
+
# chosen[2] is the index of the title column from Fzf.feature_rows
|
104
|
+
if chosen.any? && (feature = api.find_feature(chosen[2]))
|
105
|
+
Api::Feature::Viewer.new(feature).render
|
106
|
+
use
|
107
|
+
else
|
108
|
+
exit
|
109
|
+
end
|
110
|
+
end
|
75
111
|
end
|
76
112
|
|
77
|
-
def self.show(brws =
|
113
|
+
def self.show(brws = nil, version = nil)
|
78
114
|
browser = api.find_browser brws
|
79
115
|
|
80
116
|
if browser
|
@@ -83,14 +119,14 @@ module Cani
|
|
83
119
|
header: "show:#{browser.title.downcase}:#{version}] [#{Api::Feature.support_legend}",
|
84
120
|
colors: [:green, :light_black, :light_white]
|
85
121
|
|
86
|
-
show browser.title
|
122
|
+
show browser.title
|
87
123
|
else
|
88
124
|
if (version = Fzf.pick(Fzf.browser_usage_rows(browser),
|
89
125
|
header: [:show, browser.title],
|
90
126
|
colors: %i[white light_black]).first)
|
91
127
|
show browser.title, version
|
92
128
|
else
|
93
|
-
show
|
129
|
+
show
|
94
130
|
end
|
95
131
|
end
|
96
132
|
else
|
@@ -98,7 +134,7 @@ module Cani
|
|
98
134
|
header: [:show],
|
99
135
|
colors: %i[white light_black]).first
|
100
136
|
|
101
|
-
show browser.title
|
137
|
+
show browser.title unless browser.nil?
|
102
138
|
end
|
103
139
|
end
|
104
140
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cani
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sidney Liebrand
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-07-
|
11
|
+
date: 2018-07-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: colorize
|
@@ -25,7 +25,7 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: curses
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
@@ -39,33 +39,33 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: json
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
48
|
-
type: :
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: bundler
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
61
|
+
version: '1.16'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
68
|
+
version: '1.16'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: pry
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,6 +80,20 @@ dependencies:
|
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '10.0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '10.0'
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
98
|
name: rspec
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -118,9 +132,10 @@ files:
|
|
118
132
|
- lib/cani.rb
|
119
133
|
- lib/cani/api.rb
|
120
134
|
- lib/cani/api/browser.rb
|
121
|
-
- lib/cani/api/config.rb
|
122
135
|
- lib/cani/api/feature.rb
|
136
|
+
- lib/cani/api/feature/viewer.rb
|
123
137
|
- lib/cani/completions.rb
|
138
|
+
- lib/cani/config.rb
|
124
139
|
- lib/cani/fzf.rb
|
125
140
|
- lib/cani/version.rb
|
126
141
|
- shell/completions/functions.bash
|
data/lib/cani/api/config.rb
DELETED
@@ -1,121 +0,0 @@
|
|
1
|
-
module Cani
|
2
|
-
class Api
|
3
|
-
class Config
|
4
|
-
attr_reader :settings
|
5
|
-
|
6
|
-
FILE = File.join(Dir.home, '.config', 'cani', 'config.yml').freeze
|
7
|
-
DIRECTORY = File.dirname(FILE).freeze
|
8
|
-
COMP_DIR = File.join(DIRECTORY, 'completions').freeze
|
9
|
-
FISH_DIR = File.join(Dir.home, '.config', 'fish').freeze
|
10
|
-
FISH_COMP_DIR = File.join(FISH_DIR, 'completions').freeze
|
11
|
-
DEFAULTS = {
|
12
|
-
# data settings
|
13
|
-
'expire' => 86_400,
|
14
|
-
'source' => 'https://raw.githubusercontent.com/Fyrd/caniuse/master/data.json',
|
15
|
-
|
16
|
-
# usage settings
|
17
|
-
'versions' => 1,
|
18
|
-
'browsers' => %w[chrome firefox edge ie safari ios_saf opera android bb]
|
19
|
-
}.freeze
|
20
|
-
|
21
|
-
def initialize(**opts)
|
22
|
-
@settings = DEFAULTS.merge opts
|
23
|
-
|
24
|
-
if File.exist? file
|
25
|
-
if (yml = YAML.load_file(file))
|
26
|
-
@settings.merge! yml
|
27
|
-
end
|
28
|
-
else
|
29
|
-
install!
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def file
|
34
|
-
FILE
|
35
|
-
end
|
36
|
-
|
37
|
-
def directory
|
38
|
-
DIRECTORY
|
39
|
-
end
|
40
|
-
|
41
|
-
def comp_dir
|
42
|
-
COMP_DIR
|
43
|
-
end
|
44
|
-
|
45
|
-
def fish_dir
|
46
|
-
FISH_DIR
|
47
|
-
end
|
48
|
-
|
49
|
-
def fish_comp_dir
|
50
|
-
FISH_COMP_DIR
|
51
|
-
end
|
52
|
-
|
53
|
-
def flags
|
54
|
-
@flags ||= ARGV.select { |arg| arg.start_with? '-' }
|
55
|
-
end
|
56
|
-
|
57
|
-
def args
|
58
|
-
@args ||= ARGV.reject { |arg| arg.start_with? '-' }
|
59
|
-
end
|
60
|
-
|
61
|
-
def remove!
|
62
|
-
File.unlink file if File.exist? file
|
63
|
-
FileUtils.rm_rf directory if Dir.exist? directory
|
64
|
-
end
|
65
|
-
|
66
|
-
def install!
|
67
|
-
hrs = (DEFAULTS['expire'] / 3600.to_f).round 2
|
68
|
-
days = (hrs / 24.to_f).round 2
|
69
|
-
wk = (days / 7.to_f).round 2
|
70
|
-
mo = (days / 30.to_f).round 2
|
71
|
-
tstr = if mo >= 1
|
72
|
-
"#{mo == mo.to_i ? mo.to_i : mo} month#{mo != 1 ? 's' : ''}"
|
73
|
-
elsif wk >= 1
|
74
|
-
"#{wk == wk.to_i ? wk.to_i : wk} week#{wk != 1 ? 's' : ''}"
|
75
|
-
elsif days >= 1
|
76
|
-
"#{days == days.to_i ? days.to_i : days} day#{days != 1 ? 's' : ''}"
|
77
|
-
else
|
78
|
-
"#{hrs == hrs.to_i ? hrs.to_i : hrs} hour#{hrs != 1 ? 's' : ''}"
|
79
|
-
end
|
80
|
-
|
81
|
-
FileUtils.mkdir_p directory
|
82
|
-
File.open file, 'w' do |f|
|
83
|
-
f << "---\n"
|
84
|
-
f << "# this is the default configuration file for the \"Cani\" RubyGem.\n"
|
85
|
-
f << "# it contains some options to control what is shown, when new data\n"
|
86
|
-
f << "# is fetched, where it should be fetched from.\n"
|
87
|
-
f << "# documentation: https://github.com/sidofc/cani\n"
|
88
|
-
f << "# rubygems: https://rubygems.org/gems/cani\n\n"
|
89
|
-
f << "# the \"expire\" key defines the interval at which new data is\n"
|
90
|
-
f << "# fetched from \"source\". It's value is passed in as seconds\n"
|
91
|
-
f << "# default value: #{DEFAULTS['expire']} # => #{tstr}\n"
|
92
|
-
f << "expire: #{expire}\n\n"
|
93
|
-
f << "# the \"source\" key is used to fetch the data required for\n"
|
94
|
-
f << "# this command to work.\n"
|
95
|
-
f << "source: #{source}\n\n"
|
96
|
-
f << "# the \"versions\" key defines how many versions of support\n"
|
97
|
-
f << "# will be shown in the \"use\" command\n"
|
98
|
-
f << "# e.g. `-ie +edge` becomes `--ie ++edge` when this is set to 2, etc..."
|
99
|
-
f << "versions: #{versions}\n\n"
|
100
|
-
f << "# the \"browsers\" key defines which browsers are shown\n"
|
101
|
-
f << "# in the \"use\" command\n"
|
102
|
-
f << "browsers:\n"
|
103
|
-
f << " # enabled:\n"
|
104
|
-
f << browsers.map { |bn| " - #{bn}" }.join("\n") + "\n"
|
105
|
-
f << " # others:\n"
|
106
|
-
f << (Cani.api.browsers.map(&:name) - browsers).map { |bn| " # - #{bn}" }.join("\n")
|
107
|
-
end
|
108
|
-
|
109
|
-
Completions.install!
|
110
|
-
end
|
111
|
-
|
112
|
-
def method_missing(mtd, *args, &block)
|
113
|
-
settings.key?(mtd.to_s) ? settings[mtd.to_s] : super
|
114
|
-
end
|
115
|
-
|
116
|
-
def respond_to_missing?(mtd, include_private = false)
|
117
|
-
settings.key? mtd.to_s
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|