lexdrill 0.19.0 → 0.21.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/README.md +3 -2
- data/lib/lexdrill/cli.rb +31 -25
- data/lib/lexdrill/inspector.rb +5 -0
- data/lib/lexdrill/remote_target.rb +33 -0
- data/lib/lexdrill/sheets_client.rb +7 -0
- data/lib/lexdrill/version.rb +1 -1
- data/lib/lexdrill.rb +1 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 03c53271701afc42f6f8b239bd2fb8c85d5d88a55d72c7781573504241d1ad1c
|
|
4
|
+
data.tar.gz: 231518970e268aa36342feda3885f0771293a0042df918c28b17a63a136ab001
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b1b115d135527fbc032faa1ad8ea63b48708eda8ce9a9ce8501d59f95f315ab191545a4b8d355d0ab54c2b924ee1267a4873239bc779c8e5290e6f76d16d539f
|
|
7
|
+
data.tar.gz: 3a038930e2e0a901b1d09227bda97588d7eb2073418156c05151e663413cb0f01c20fbf0457335d5386c6ff20c17e629a2d30c070c41167aea1c132f888499a0
|
data/README.md
CHANGED
|
@@ -280,7 +280,7 @@ itself automatically).
|
|
|
280
280
|
|---|---|
|
|
281
281
|
| `drill next` | Print the current word and advance |
|
|
282
282
|
| `drill start` / `drill stop` | Pause/resume the automatic per-prompt hook (doesn't affect manual `next`) |
|
|
283
|
-
| `drill inspect` | Show the active config directory, word count, counter value, toggle, beat, rand, and
|
|
283
|
+
| `drill inspect` | Show the active config directory, word count, counter value, toggle, beat, rand, color, and remote state |
|
|
284
284
|
| `drill hook zsh\|bash` | Print the shell integration snippet (used above) |
|
|
285
285
|
| `drill beat <2-8> <repetitions>` / `drill beat none` | Set or disable the rhythm |
|
|
286
286
|
| `drill polka\|waltz\|rock\|jazz\|jiga\|balkan\|samba <repetitions>` | Shorthand for a fixed loop size (see table above) |
|
|
@@ -293,6 +293,7 @@ itself automatically).
|
|
|
293
293
|
| `drill go <number>` | Jump so the next `drill next` shows item `<number>` (1-based, see `drill list`) — prints nothing itself; refuses a graduated item; has no effect while `drill beat rand` is active, since that mode ignores the counter entirely |
|
|
294
294
|
| `drill remote <url>` | Set the Google Sheet used by the service account flow (global, parses the spreadsheet id out of a normal share URL); whichever of `drill remote`/`drill oauth` was set more recently wins |
|
|
295
295
|
| `drill oauth <url>` | Set the Google Sheet used by the OAuth (personal-login) flow (global, parses the spreadsheet id out of a normal share URL); whichever of `drill remote`/`drill oauth` was set more recently wins |
|
|
296
|
-
| `drill
|
|
296
|
+
| `drill wb` | Print a link to whichever workbook (spreadsheet) is currently active (`drill remote`/`drill oauth`) |
|
|
297
|
+
| `drill sheets` | List the tab names in the currently active workbook |
|
|
297
298
|
| `drill export <sheet-name>` | Export the word list text to the named tab (created if it doesn't exist), overwriting it; uses whichever of `drill remote`/`drill oauth` was configured most recently (first OAuth use triggers a one-time Google device-flow sign-in) |
|
|
298
299
|
| `drill import <sheet-name>` | Replace the local word list with column A of the named tab |
|
data/lib/lexdrill/cli.rb
CHANGED
|
@@ -20,7 +20,8 @@ class Lexdrill::CLI
|
|
|
20
20
|
run_go: %w[go],
|
|
21
21
|
run_remote: %w[remote],
|
|
22
22
|
run_oauth: %w[oauth],
|
|
23
|
-
|
|
23
|
+
run_wb: %w[wb],
|
|
24
|
+
run_sheets: %w[sheets],
|
|
24
25
|
run_export: %w[export],
|
|
25
26
|
run_import: %w[import]
|
|
26
27
|
}.freeze
|
|
@@ -77,7 +78,8 @@ class Lexdrill::CLI
|
|
|
77
78
|
drill remote <url> Set the Google Sheet used by a local service account key
|
|
78
79
|
(~/.drill/gcp-service-account.json) — no interactive sign-in
|
|
79
80
|
drill oauth <url> Set the Google Sheet used by the OAuth (personal-login) flow
|
|
80
|
-
drill
|
|
81
|
+
drill wb Print a link to the currently active workbook (spreadsheet)
|
|
82
|
+
drill sheets List the tab names in the currently active workbook
|
|
81
83
|
drill export <sheet-name> Export the word list text to the given tab (overwrites its
|
|
82
84
|
contents); uses whichever of drill remote/drill oauth was set
|
|
83
85
|
more recently (oauth opens a one-time sign-in on first use)
|
|
@@ -343,37 +345,36 @@ class Lexdrill::CLI
|
|
|
343
345
|
# either command always takes effect. Returns [spreadsheet_id,
|
|
344
346
|
# access_token], or nil if neither is configured.
|
|
345
347
|
def sheets_target
|
|
346
|
-
kind =
|
|
347
|
-
spreadsheet_id =
|
|
348
|
+
kind = Lexdrill::RemoteTarget.kind
|
|
349
|
+
spreadsheet_id = Lexdrill::RemoteTarget.spreadsheet_id
|
|
348
350
|
return unless spreadsheet_id
|
|
349
351
|
|
|
350
352
|
[spreadsheet_id, kind == :remote ? Lexdrill::ServiceAccountAuth.fetch_token! : Lexdrill::GoogleAuth.ensure_token!]
|
|
351
353
|
end
|
|
352
354
|
|
|
353
|
-
def
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
when :oauth then Lexdrill::OauthRemote.spreadsheet_id
|
|
357
|
-
end
|
|
358
|
-
end
|
|
355
|
+
def run_wb
|
|
356
|
+
url = Lexdrill::RemoteTarget.url
|
|
357
|
+
return print_no_remote unless url
|
|
359
358
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
oauth_set = Lexdrill::OauthRemote.configured?
|
|
363
|
-
return :remote if remote_set && (!oauth_set || newer?(Lexdrill::Remote::PATH, Lexdrill::OauthRemote::PATH))
|
|
364
|
-
return :oauth if oauth_set
|
|
365
|
-
|
|
366
|
-
nil
|
|
359
|
+
puts url
|
|
360
|
+
0
|
|
367
361
|
end
|
|
368
362
|
|
|
369
|
-
def
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
spreadsheet_id = spreadsheet_id_for(latest_remote_kind)
|
|
373
|
-
return print_no_remote unless spreadsheet_id
|
|
363
|
+
def run_sheets
|
|
364
|
+
target = sheets_target
|
|
365
|
+
return print_no_remote unless target
|
|
374
366
|
|
|
375
|
-
|
|
367
|
+
spreadsheet_id, token = target
|
|
368
|
+
Lexdrill::SheetsClient.sheet_titles(spreadsheet_id, token).each { |title| puts title }
|
|
376
369
|
0
|
|
370
|
+
rescue Lexdrill::GoogleAuth::AuthError, Lexdrill::ServiceAccountAuth::AuthError => error
|
|
371
|
+
warn "drill: #{error.message}"
|
|
372
|
+
1
|
|
373
|
+
rescue Lexdrill::SheetsClient::ApiError => error
|
|
374
|
+
print_sheets_api_error(error)
|
|
375
|
+
rescue Lexdrill::HTTPClient::NetworkError => error
|
|
376
|
+
warn "drill: network error talking to Google (#{error.message})"
|
|
377
|
+
1
|
|
377
378
|
end
|
|
378
379
|
|
|
379
380
|
def run_export
|
|
@@ -453,18 +454,23 @@ class Lexdrill::CLI
|
|
|
453
454
|
1
|
|
454
455
|
end
|
|
455
456
|
|
|
456
|
-
def print_sheets_api_error(error, sheet_name)
|
|
457
|
+
def print_sheets_api_error(error, sheet_name = nil)
|
|
457
458
|
status = error.status
|
|
458
459
|
message = error.message
|
|
459
460
|
case status
|
|
460
461
|
when 404 then warn "drill: spreadsheet not found or not accessible (check `drill remote`/`drill oauth`)"
|
|
461
462
|
when 403 then warn "drill: access denied — make sure the spreadsheet is shared with the right account"
|
|
462
|
-
when 400 then
|
|
463
|
+
when 400 then print_400_error(message, sheet_name)
|
|
463
464
|
else warn "drill: Google Sheets API error (#{status}): #{message}"
|
|
464
465
|
end
|
|
465
466
|
1
|
|
466
467
|
end
|
|
467
468
|
|
|
469
|
+
def print_400_error(message, sheet_name)
|
|
470
|
+
hint = " (is #{sheet_name.inspect} a real tab in the spreadsheet?)" if sheet_name
|
|
471
|
+
warn "drill: #{message}#{hint}"
|
|
472
|
+
end
|
|
473
|
+
|
|
468
474
|
def print_unknown_command(command)
|
|
469
475
|
warn "drill: unknown command #{command.inspect}"
|
|
470
476
|
print_help
|
data/lib/lexdrill/inspector.rb
CHANGED
|
@@ -15,10 +15,15 @@ module Lexdrill::Inspector
|
|
|
15
15
|
Beat: #{beat_summary}
|
|
16
16
|
Rand: #{rand_summary}
|
|
17
17
|
Color: #{Lexdrill::Color.current}
|
|
18
|
+
Remote: #{remote_summary}
|
|
18
19
|
Config dir: #{Lexdrill::Config::DIR}
|
|
19
20
|
REPORT
|
|
20
21
|
end
|
|
21
22
|
|
|
23
|
+
def self.remote_summary
|
|
24
|
+
Lexdrill::RemoteTarget.url || "not configured"
|
|
25
|
+
end
|
|
26
|
+
|
|
22
27
|
def self.words_summary
|
|
23
28
|
return "missing" unless File.exist?(Lexdrill::WordList::PATH)
|
|
24
29
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Resolves which configured Google Sheet target (drill remote / drill
|
|
4
|
+
# oauth) is currently active — whichever was set more recently — so
|
|
5
|
+
# `drill export`/`drill import`, `drill sheet`, and `drill inspect` all
|
|
6
|
+
# agree on a single answer.
|
|
7
|
+
module Lexdrill::RemoteTarget
|
|
8
|
+
def self.kind
|
|
9
|
+
remote_set = Lexdrill::Remote.configured?
|
|
10
|
+
oauth_set = Lexdrill::OauthRemote.configured?
|
|
11
|
+
return :remote if remote_set && (!oauth_set || newer?(Lexdrill::Remote::PATH, Lexdrill::OauthRemote::PATH))
|
|
12
|
+
return :oauth if oauth_set
|
|
13
|
+
|
|
14
|
+
nil
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.spreadsheet_id
|
|
18
|
+
case kind
|
|
19
|
+
when :remote then Lexdrill::Remote.spreadsheet_id
|
|
20
|
+
when :oauth then Lexdrill::OauthRemote.spreadsheet_id
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.url
|
|
25
|
+
id = spreadsheet_id
|
|
26
|
+
"https://docs.google.com/spreadsheets/d/#{id}/edit" if id
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def self.newer?(path, other_path)
|
|
30
|
+
File.mtime(path) >= File.mtime(other_path)
|
|
31
|
+
end
|
|
32
|
+
private_class_method :newer?
|
|
33
|
+
end
|
|
@@ -77,6 +77,13 @@ module Lexdrill::SheetsClient
|
|
|
77
77
|
data.fetch("values", []).filter_map { |row| row[0]&.strip }.reject(&:empty?)
|
|
78
78
|
end
|
|
79
79
|
|
|
80
|
+
# The titles of every tab in the workbook, for `drill sheets`.
|
|
81
|
+
def self.sheet_titles(spreadsheet_id, access_token)
|
|
82
|
+
url = "#{BASE_URL}/#{spreadsheet_id}?fields=sheets.properties.title"
|
|
83
|
+
data = handle_response(Lexdrill::HTTPClient.json_get(url, headers: auth_header(access_token)))
|
|
84
|
+
data.fetch("sheets", []).map { |sheet| sheet.dig("properties", "title") }
|
|
85
|
+
end
|
|
86
|
+
|
|
80
87
|
def self.auth_header(token)
|
|
81
88
|
{ "Authorization" => "Bearer #{token}" }
|
|
82
89
|
end
|
data/lib/lexdrill/version.rb
CHANGED
data/lib/lexdrill.rb
CHANGED
|
@@ -11,6 +11,7 @@ require_relative "lexdrill/toggle"
|
|
|
11
11
|
require_relative "lexdrill/rand"
|
|
12
12
|
require_relative "lexdrill/remote"
|
|
13
13
|
require_relative "lexdrill/oauth_remote"
|
|
14
|
+
require_relative "lexdrill/remote_target"
|
|
14
15
|
require_relative "lexdrill/http_client"
|
|
15
16
|
require_relative "lexdrill/google_auth"
|
|
16
17
|
require_relative "lexdrill/service_account_auth"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: lexdrill
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.21.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Siarhei Kisliak
|
|
@@ -39,6 +39,7 @@ files:
|
|
|
39
39
|
- lib/lexdrill/oauth_remote.rb
|
|
40
40
|
- lib/lexdrill/rand.rb
|
|
41
41
|
- lib/lexdrill/remote.rb
|
|
42
|
+
- lib/lexdrill/remote_target.rb
|
|
42
43
|
- lib/lexdrill/service_account_auth.rb
|
|
43
44
|
- lib/lexdrill/sheets_client.rb
|
|
44
45
|
- lib/lexdrill/shell_snippet.rb
|