pennyworth 10.0.1 → 11.0.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.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/README.adoc +209 -30
  5. data/bin/pennyworth +1 -3
  6. data/lib/pennyworth.rb +11 -2
  7. data/lib/pennyworth/cli/actions/config.rb +35 -0
  8. data/lib/pennyworth/cli/actions/encodings.rb +23 -0
  9. data/lib/pennyworth/cli/actions/git_hub.rb +27 -0
  10. data/lib/pennyworth/cli/actions/http_statuses.rb +23 -0
  11. data/lib/pennyworth/cli/actions/ruby_gems.rb +27 -0
  12. data/lib/pennyworth/cli/actions/system/errors.rb +25 -0
  13. data/lib/pennyworth/cli/actions/system/signals.rb +25 -0
  14. data/lib/pennyworth/cli/actions/text.rb +23 -0
  15. data/lib/pennyworth/cli/configuration/content.rb +28 -0
  16. data/lib/pennyworth/cli/configuration/defaults.yml +25 -0
  17. data/lib/pennyworth/cli/configuration/loader.rb +37 -0
  18. data/lib/pennyworth/cli/parsers.rb +11 -0
  19. data/lib/pennyworth/cli/parsers/assembler.rb +32 -0
  20. data/lib/pennyworth/cli/parsers/core.rb +100 -0
  21. data/lib/pennyworth/cli/parsers/git_hub.rb +51 -0
  22. data/lib/pennyworth/cli/parsers/ruby_gems.rb +35 -0
  23. data/lib/pennyworth/cli/shell.rb +82 -0
  24. data/lib/pennyworth/container.rb +40 -0
  25. data/lib/pennyworth/identity.rb +2 -1
  26. data/lib/pennyworth/inflector.rb +18 -0
  27. data/lib/pennyworth/integrations/git_hub/client.rb +59 -0
  28. data/lib/pennyworth/integrations/git_hub/response.rb +33 -0
  29. data/lib/pennyworth/integrations/ruby_gems/client.rb +29 -0
  30. data/lib/pennyworth/loaders/encodings.rb +31 -0
  31. data/lib/pennyworth/loaders/http_statuses.rb +28 -0
  32. data/lib/pennyworth/loaders/projects.rb +22 -0
  33. data/lib/pennyworth/loaders/system/errors.rb +33 -0
  34. data/lib/pennyworth/loaders/system/signals.rb +21 -0
  35. data/lib/pennyworth/loaders/text.rb +27 -0
  36. data/lib/pennyworth/models/encoding.rb +8 -0
  37. data/lib/pennyworth/models/http_status.rb +8 -0
  38. data/lib/pennyworth/models/system/error.rb +10 -0
  39. data/lib/pennyworth/models/system/signal.rb +10 -0
  40. data/lib/pennyworth/models/text.rb +8 -0
  41. data/lib/pennyworth/presenters/encoding.rb +22 -0
  42. data/lib/pennyworth/presenters/gem.rb +48 -0
  43. data/lib/pennyworth/presenters/http_status.rb +41 -0
  44. data/lib/pennyworth/presenters/repository.rb +35 -0
  45. data/lib/pennyworth/presenters/system/error.rb +28 -0
  46. data/lib/pennyworth/presenters/system/signal.rb +22 -0
  47. data/lib/pennyworth/presenters/text.rb +25 -0
  48. data/lib/pennyworth/processor.rb +68 -0
  49. data/lib/pennyworth/serializers/encoding.rb +33 -0
  50. data/lib/pennyworth/serializers/http_status.rb +41 -0
  51. data/lib/pennyworth/serializers/project.rb +52 -0
  52. data/lib/pennyworth/serializers/system/error.rb +46 -0
  53. data/lib/pennyworth/serializers/system/signal.rb +40 -0
  54. data/lib/pennyworth/serializers/text.rb +31 -0
  55. metadata +110 -19
  56. metadata.gz.sig +2 -2
  57. data/lib/pennyworth/cli.rb +0 -140
  58. data/lib/pennyworth/templates/workflows/user.workflow.B59B22A2-1880-4765-9358-412791BE9202/icon.png +0 -0
  59. data/lib/pennyworth/templates/workflows/user.workflow.B59B22A2-1880-4765-9358-412791BE9202/info.plist +0 -159
  60. data/lib/pennyworth/templates/workflows/user.workflow.C431E56A-0EC2-47EE-94D5-D67D9FE323BE/icon.png +0 -0
  61. data/lib/pennyworth/templates/workflows/user.workflow.C431E56A-0EC2-47EE-94D5-D67D9FE323BE/info.plist +0 -272
  62. data/lib/pennyworth/templates/workflows/user.workflow.C431E56A-0EC2-47EE-94D5-D67D9FE323BE/string-camelcase.png +0 -0
  63. data/lib/pennyworth/templates/workflows/user.workflow.C431E56A-0EC2-47EE-94D5-D67D9FE323BE/string-capitalize.png +0 -0
  64. data/lib/pennyworth/templates/workflows/user.workflow.C431E56A-0EC2-47EE-94D5-D67D9FE323BE/string-lowercase.png +0 -0
  65. data/lib/pennyworth/templates/workflows/user.workflow.C431E56A-0EC2-47EE-94D5-D67D9FE323BE/string-size.png +0 -0
  66. data/lib/pennyworth/templates/workflows/user.workflow.C431E56A-0EC2-47EE-94D5-D67D9FE323BE/string-snakecase.png +0 -0
  67. data/lib/pennyworth/templates/workflows/user.workflow.C431E56A-0EC2-47EE-94D5-D67D9FE323BE/string-titleize.png +0 -0
  68. data/lib/pennyworth/templates/workflows/user.workflow.C431E56A-0EC2-47EE-94D5-D67D9FE323BE/string-uppercase.png +0 -0
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry-container"
4
+ require "logger"
5
+ require "http"
6
+ require "pastel"
7
+
8
+ module Pennyworth
9
+ # Provides a global gem container for injection into other objects.
10
+ module Container
11
+ extend Dry::Container::Mixin
12
+
13
+ register(:configuration) { CLI::Configuration::Loader.call }
14
+ register(:environment) { ENV }
15
+ register(:kernel) { Kernel }
16
+ register(:http) { HTTP }
17
+ register(:colorizer) { Pastel.new enabled: $stdout.tty? }
18
+
19
+ register :log_colors do
20
+ {
21
+ "DEBUG" => self[:colorizer].white.detach,
22
+ "INFO" => self[:colorizer].green.detach,
23
+ "WARN" => self[:colorizer].yellow.detach,
24
+ "ERROR" => self[:colorizer].red.detach,
25
+ "FATAL" => self[:colorizer].white.bold.on_red.detach,
26
+ "ANY" => self[:colorizer].white.bold.detach
27
+ }
28
+ end
29
+
30
+ register :logger do
31
+ Logger.new $stdout,
32
+ level: Logger.const_get(ENV.fetch("LOG_LEVEL", "INFO")),
33
+ formatter: (
34
+ lambda do |severity, _at, _name, message|
35
+ self[:log_colors][severity].call "#{message}\n"
36
+ end
37
+ )
38
+ end
39
+ end
40
+ end
@@ -5,7 +5,8 @@ module Pennyworth
5
5
  module Identity
6
6
  NAME = "pennyworth"
7
7
  LABEL = "Pennyworth"
8
- VERSION = "10.0.1"
8
+ SUMMARY = "A command line interface that augments Alfred workflows."
9
+ VERSION = "11.0.0"
9
10
  VERSION_LABEL = "#{LABEL} #{VERSION}"
10
11
  end
11
12
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pennyworth
4
+ # Overrides any string to desired form if matched, otherwise answers the original string.
5
+ class Inflector
6
+ DEFAULTS = Array(CLI::Configuration::Loader.call.inflections).reduce({}, :merge)
7
+
8
+ def initialize overrides = DEFAULTS
9
+ @overrides = overrides
10
+ end
11
+
12
+ def call(key) = overrides.fetch(key) { |missing_key| missing_key }
13
+
14
+ private
15
+
16
+ attr_reader :overrides
17
+ end
18
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "refinements/arrays"
4
+
5
+ module Pennyworth
6
+ module Integrations
7
+ module GitHub
8
+ # Provides low-level API access to the GitHub API.
9
+ class Client
10
+ using Refinements::Arrays
11
+
12
+ HEADERS = {
13
+ accept: "application/vnd.github.v3+json",
14
+ content_type: "Content-Type: application/json; charset=utf-8"
15
+ }.freeze
16
+
17
+ def initialize headers: HEADERS, container: Container
18
+ @headers = headers
19
+ @container = container
20
+ end
21
+
22
+ def get endpoint, parameters: {}
23
+ paginate ->(page) { sole_get endpoint, parameters: parameters.merge(page: page) }
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :headers, :container
29
+
30
+ # :reek:FeatureEnvy
31
+ def paginate request, records: [], page: 1
32
+ response = request.call page
33
+
34
+ records.including(response.records)
35
+ .then do |updated_records|
36
+ return updated_records if response.last_page.zero?
37
+
38
+ paginate request, records: updated_records, page: response.next_page
39
+ end
40
+ end
41
+
42
+ def sole_get endpoint, parameters: {}
43
+ http.headers(headers)
44
+ .basic_auth(user: api_login, pass: api_token)
45
+ .get("#{api_url}/#{endpoint}", params: parameters)
46
+ .then { |response| Response.new response }
47
+ end
48
+
49
+ def http = container[__method__]
50
+
51
+ def api_url = container[:configuration].git_hub_api_url
52
+
53
+ def api_login = container[:environment].fetch("GITHUB_API_LOGIN")
54
+
55
+ def api_token = container[:environment].fetch("GITHUB_API_TOKEN")
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pennyworth
4
+ module Integrations
5
+ module GitHub
6
+ # Represents a generic GitHub API response.
7
+ class Response
8
+ def initialize raw
9
+ @raw = raw
10
+ end
11
+
12
+ def next_page = page("next")
13
+
14
+ def last_page = page("last")
15
+
16
+ def records = success? ? JSON(raw.body, symbolize_names: true) : []
17
+
18
+ def success? = raw.status.success?
19
+
20
+ private
21
+
22
+ attr_reader :raw
23
+
24
+ def page reference
25
+ links.find { |link| link.include? reference }
26
+ .then { |link| String(link)[/page=(?<page>\d+)/, :page].to_i }
27
+ end
28
+
29
+ def links = String(raw.headers["Link"]).split(", ")
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pennyworth
4
+ module Integrations
5
+ module RubyGems
6
+ # Provides low-level API access to the RubyGems API.
7
+ class Client
8
+ def initialize container: Container
9
+ @container = container
10
+ end
11
+
12
+ def get endpoint
13
+ http.get("#{api_url}/#{endpoint}")
14
+ .then do |response|
15
+ response.status.success? ? JSON(response.body.to_s, symbolize_names: true) : {}
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ attr_reader :container
22
+
23
+ def http = container[__method__]
24
+
25
+ def api_url = container[:configuration].ruby_gems_api_url
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "refinements/arrays"
4
+
5
+ module Pennyworth
6
+ module Loaders
7
+ # Loads an array of encoding records.
8
+ class Encodings
9
+ using Refinements::Arrays
10
+
11
+ def initialize encoding: Encoding, model: Models::Encoding
12
+ @encoding = encoding
13
+ @model = model
14
+ end
15
+
16
+ def call _omit = nil
17
+ encoding.aliases
18
+ .map { |_second, first| first }
19
+ .uniq
20
+ .sort
21
+ .map do |first|
22
+ model[name: first, aliases: encoding.find(first).names.sort.excluding(first)]
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :encoding, :model
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rack"
4
+
5
+ module Pennyworth
6
+ module Loaders
7
+ # Loads an array of HTTP status records.
8
+ class HTTPStatuses
9
+ def initialize codes: Rack::Utils::HTTP_STATUS_CODES,
10
+ model: Models::HTTPStatus,
11
+ configuration: CLI::Configuration::Loader.call
12
+ @codes = codes
13
+ @model = model
14
+ @configuration = configuration
15
+ end
16
+
17
+ def call _omit = nil
18
+ codes.map { |(code, label)| model[code: code, label: label, url: "#{url}/#{code}"] }
19
+ end
20
+
21
+ private
22
+
23
+ attr_reader :codes, :model, :configuration
24
+
25
+ def url = configuration.http_statuses_url
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pennyworth
4
+ module Loaders
5
+ # Loads projects from API requests for further processing.
6
+ class Projects
7
+ def self.for_git_hub = new(client: Integrations::GitHub::Client.new)
8
+
9
+ def self.for_ruby_gems = new(client: Integrations::RubyGems::Client.new)
10
+
11
+ def initialize client:
12
+ @client = client
13
+ end
14
+
15
+ def call(endpoint) = client.get(endpoint)
16
+
17
+ private
18
+
19
+ attr_reader :client
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "refinements/arrays"
4
+
5
+ module Pennyworth
6
+ module Loaders
7
+ module System
8
+ # Loads an array of system error records.
9
+ class Errors
10
+ using Refinements::Arrays
11
+
12
+ def initialize errno: Errno, model: Models::System::Error
13
+ @errno = errno
14
+ @model = model
15
+ end
16
+
17
+ def call _omit = nil
18
+ errno.constants
19
+ .map { |name| errno.const_get name }
20
+ .uniq
21
+ .sort_by { |error| error::Errno }
22
+ .map do |error|
23
+ model[id: error::Errno, name: error.name, description: error.exception.message]
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ attr_reader :errno, :model
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pennyworth
4
+ module Loaders
5
+ module System
6
+ # Loads an array of signal records.
7
+ class Signals
8
+ def initialize list: Signal.list, model: Models::System::Signal
9
+ @list = list
10
+ @model = model
11
+ end
12
+
13
+ def call(_omit = nil) = list.map { |name, number| model[number: number, name: name] }
14
+
15
+ private
16
+
17
+ attr_reader :list, :model
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "refinements/strings"
4
+
5
+ module Pennyworth
6
+ module Loaders
7
+ # Loads an array of text records.
8
+ class Text
9
+ using Refinements::Strings
10
+
11
+ TRANSFORMS = %w[camelcase capitalize downcase size snakecase titleize upcase].freeze
12
+
13
+ def initialize transforms: TRANSFORMS, model: Models::Text
14
+ @transforms = transforms
15
+ @model = model
16
+ end
17
+
18
+ def call content
19
+ transforms.map { |kind| model[id: kind, content: content.public_send(kind)] }
20
+ end
21
+
22
+ private
23
+
24
+ attr_reader :transforms, :model
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pennyworth
4
+ module Models
5
+ # Defines an encoding.
6
+ Encoding = Struct.new :name, :aliases, keyword_init: true
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pennyworth
4
+ module Models
5
+ # Defines HTTP status details.
6
+ HTTPStatus = Struct.new :code, :label, :url, keyword_init: true
7
+ end
8
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pennyworth
4
+ module Models
5
+ module System
6
+ # Defines a system error.
7
+ Error = Struct.new :id, :name, :description, keyword_init: true
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pennyworth
4
+ module Models
5
+ module System
6
+ # Defines a low-level operating system signal.
7
+ Signal = Struct.new :number, :name, keyword_init: true
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pennyworth
4
+ module Models
5
+ # Defines basic text.
6
+ Text = Struct.new :id, :content, keyword_init: true
7
+ end
8
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pennyworth
4
+ module Presenters
5
+ # Renders encoding into a compatible format for use in Alfred script filters.
6
+ class Encoding
7
+ def initialize record
8
+ @record = record
9
+ end
10
+
11
+ def id = record.name
12
+
13
+ def label = record.name
14
+
15
+ def aliases = record.aliases
16
+
17
+ private
18
+
19
+ attr_reader :record
20
+ end
21
+ end
22
+ end