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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2c04d80068319a1be565d64c8325ce808f242d7a71609f34796b348cc04b0571
4
- data.tar.gz: 2b06d6b6d48cc3556c77524bce72c77e18404aceadd802cb3ae40134a29cfc3d
3
+ metadata.gz: 03c53271701afc42f6f8b239bd2fb8c85d5d88a55d72c7781573504241d1ad1c
4
+ data.tar.gz: 231518970e268aa36342feda3885f0771293a0042df918c28b17a63a136ab001
5
5
  SHA512:
6
- metadata.gz: c15dac65d6521acd98fb4a81f016466882d4397587a9de255544364cbcb0a9bc535e399c91dd7979ea4fadc5206ca86c4c2f04db62898baa298d2a82a24f908d
7
- data.tar.gz: b8f7dd159de9b89f81cafd9a73d50d2e7db6541ed3fcd0028f4dbee6b344301f085e3be7f7c78a669bb1494845afc65eaba886f17a164355dd99521a9a6d4c6b
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 color state |
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 sheet` | Print a link to whichever spreadsheet (`drill remote`/`drill oauth`) is currently active |
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
- run_sheet: %w[sheet],
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 sheet Print a link to the currently active spreadsheet
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 = latest_remote_kind
347
- spreadsheet_id = spreadsheet_id_for(kind)
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 spreadsheet_id_for(kind)
354
- case kind
355
- when :remote then Lexdrill::Remote.spreadsheet_id
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
- def latest_remote_kind
361
- remote_set = Lexdrill::Remote.configured?
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 newer?(path, other_path) = File.mtime(path) >= File.mtime(other_path)
370
-
371
- def run_sheet
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
- puts "https://docs.google.com/spreadsheets/d/#{spreadsheet_id}/edit"
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 warn "drill: #{message} (is #{sheet_name.inspect} a real tab in the spreadsheet?)"
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
@@ -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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Lexdrill
4
- VERSION = "0.19.0"
4
+ VERSION = "0.21.0"
5
5
  end
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.19.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