ruby_git_crypt 0.1.0.pre.1

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.
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module RubyGitCrypt
6
+ module Commands
7
+ class Status < Base
8
+ # @!visibility private
9
+ def subcommands
10
+ %w[status]
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'commands/status'
4
+
5
+ module RubyGitCrypt
6
+ module Commands
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyGitCrypt
4
+ module Errors
5
+ class ExecutionError < StandardError
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'errors/execution_error'
4
+
5
+ module RubyGitCrypt
6
+ module Errors
7
+ end
8
+ end
@@ -0,0 +1,176 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'immutable-struct'
4
+
5
+ require_relative './name'
6
+ require_relative './types'
7
+ require_relative './values'
8
+
9
+ module RubyGitCrypt
10
+ module Options
11
+ # rubocop:disable Metrics/ClassLength
12
+ class Definition < ImmutableStruct.new(
13
+ :name,
14
+ :option_type,
15
+ :value_type,
16
+ :override_keys,
17
+ :extra_keys,
18
+ :separator,
19
+ :placement,
20
+ :repeatable?
21
+ )
22
+ # rubocop:disable Metrics/MethodLength
23
+ def initialize(opts)
24
+ raise 'Missing name.' unless opts[:name]
25
+
26
+ super(
27
+ name: Name.new(opts[:name]),
28
+ option_type: Types.resolve(opts[:option_type]) || Types::Standard,
29
+ value_type: Values.resolve(opts[:value_type]) || Values::String,
30
+ repeatable: opts[:repeatable] || false,
31
+ separator: opts[:separator],
32
+ placement: opts[:placement],
33
+ extra_keys:
34
+ { singular: [], plural: [] }
35
+ .merge(opts[:extra_keys] || {}),
36
+ override_keys:
37
+ { singular: nil, plural: nil }
38
+ .merge(opts[:override_keys] || {})
39
+ )
40
+ end
41
+
42
+ # rubocop:enable Metrics/MethodLength
43
+
44
+ def matches?(name)
45
+ @name == Name.new(name)
46
+ end
47
+
48
+ def build(parameters)
49
+ build_singular_options(parameters) + build_plural_options(parameters)
50
+ end
51
+
52
+ private
53
+
54
+ def resolved_singular_key
55
+ if override_keys[:singular] == false
56
+ nil
57
+ else
58
+ override_keys[:singular] || name.as_singular_key
59
+ end
60
+ end
61
+
62
+ def all_singular_keys
63
+ ([resolved_singular_key] + extra_keys[:singular]).compact
64
+ end
65
+
66
+ def resolved_plural_key
67
+ if override_keys[:plural] == false
68
+ nil
69
+ else
70
+ override_keys[:plural] || name.as_plural_key
71
+ end
72
+ end
73
+
74
+ def all_plural_keys
75
+ ([resolved_plural_key] + extra_keys[:plural]).compact
76
+ end
77
+
78
+ def too_many_values?(values)
79
+ !repeatable? && values.length > 1
80
+ end
81
+
82
+ def values(parameters, keys)
83
+ keys.map { |k| parameters[k] }.compact
84
+ end
85
+
86
+ def needs_plural?(value)
87
+ repeatable? && !value.nil?
88
+ end
89
+
90
+ def only_singular?(value)
91
+ !needs_plural?(value)
92
+ end
93
+
94
+ def key_valued?(value)
95
+ value.respond_to?(:keys)
96
+ end
97
+
98
+ def multi_valued?(value)
99
+ value.respond_to?(:each)
100
+ end
101
+
102
+ def build_option(value)
103
+ option_type.new(name, value, separator: separator,
104
+ placement: placement)
105
+ end
106
+
107
+ def build_value(value)
108
+ value_type.new(value)
109
+ end
110
+
111
+ def build_key_value(key, value)
112
+ Values::KeyValue.new(key, build_value(value))
113
+ end
114
+
115
+ def build_singular(value)
116
+ build_single_option(value)
117
+ end
118
+
119
+ def build_singulars(values)
120
+ values.map { |p| build_singular(p) }.flatten
121
+ end
122
+
123
+ def build_singular_options(parameters)
124
+ keys = all_singular_keys
125
+ values = values(parameters, keys)
126
+
127
+ if too_many_values?(values)
128
+ raise "Multiple values provided for '#{name}' " \
129
+ "(with keys #{keys}) and option not repeatable."
130
+ end
131
+
132
+ build_singulars(values)
133
+ end
134
+
135
+ def build_plural(value)
136
+ if only_singular?(value)
137
+ build_no_options
138
+ elsif key_valued?(value)
139
+ build_key_value_options(value)
140
+ elsif multi_valued?(value)
141
+ build_multiple_options(value)
142
+ else
143
+ build_single_option(value)
144
+ end
145
+ end
146
+
147
+ def build_plurals(values)
148
+ values.map { |p| build_plural(p) }.flatten
149
+ end
150
+
151
+ def build_plural_options(parameters)
152
+ keys = all_plural_keys
153
+ values = values(parameters, keys)
154
+
155
+ build_plurals(values)
156
+ end
157
+
158
+ def build_key_value_options(value)
159
+ value.map { |k, v| build_option(build_key_value(k, v)) }
160
+ end
161
+
162
+ def build_multiple_options(value)
163
+ value.map { |v| build_option(build_value(v)) }
164
+ end
165
+
166
+ def build_single_option(value)
167
+ [build_option(build_value(value))]
168
+ end
169
+
170
+ def build_no_options
171
+ []
172
+ end
173
+ end
174
+ # rubocop:enable Metrics/ClassLength
175
+ end
176
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyGitCrypt
4
+ module Options
5
+ DEFINITIONS = [].freeze
6
+ end
7
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'name'
4
+
5
+ module RubyGitCrypt
6
+ module Options
7
+ class Factory
8
+ def initialize(definitions)
9
+ @definitions = definitions
10
+ end
11
+
12
+ def resolve(names, parameters)
13
+ names
14
+ .map { |name| Name.new(name) }
15
+ .inject([]) do |options, name|
16
+ options + resolve_name(name, parameters)
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def resolve_name(name, parameters)
23
+ @definitions.find { |d| d.matches?(name) }.build(parameters)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'immutable-struct'
4
+
5
+ module RubyGitCrypt
6
+ module Options
7
+ class Name < ImmutableStruct.new(:name)
8
+ def initialize(name)
9
+ super(name: name.to_s)
10
+ end
11
+
12
+ def name
13
+ "--#{without_prefix}"
14
+ end
15
+
16
+ alias to_s name
17
+
18
+ def as_singular_key
19
+ snake_case.to_sym
20
+ end
21
+
22
+ def as_plural_key
23
+ "#{snake_case}s".to_sym
24
+ end
25
+
26
+ private
27
+
28
+ def without_prefix
29
+ @name.sub(/^-+/, '')
30
+ end
31
+
32
+ def snake_case
33
+ without_prefix.gsub('-', '_')
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyGitCrypt
4
+ module Options
5
+ module Sets
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyGitCrypt
4
+ module Options
5
+ module Types
6
+ class Flag < ImmutableStruct.new(
7
+ :name,
8
+ :value
9
+ )
10
+ def initialize(name, value, **_opts)
11
+ super(name: name, value: value)
12
+ end
13
+
14
+ def apply(builder)
15
+ value.resolve ? builder.with_flag(name) : builder
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyGitCrypt
4
+ module Options
5
+ module Types
6
+ class Standard < ImmutableStruct.new(
7
+ :name,
8
+ :value,
9
+ :separator,
10
+ :placement
11
+ )
12
+ def initialize(name, value, **opts)
13
+ super(
14
+ name: name, value: value,
15
+ separator: opts[:separator],
16
+ placement: opts[:placement]
17
+ )
18
+ end
19
+
20
+ def apply(builder)
21
+ builder.with_option(
22
+ name,
23
+ value.render,
24
+ separator: separator,
25
+ placement: placement
26
+ )
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'types/standard'
4
+ require_relative 'types/flag'
5
+
6
+ module RubyGitCrypt
7
+ module Options
8
+ module Types
9
+ def self.standard(name, value, **opts)
10
+ Standard.new(name, value, **opts)
11
+ end
12
+
13
+ def self.flag(name, value)
14
+ Flag.new(name, value)
15
+ end
16
+
17
+ def self.resolve(type)
18
+ case type
19
+ when :standard then Types::Standard
20
+ when :flag then Types::Flag
21
+ else type
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'immutable-struct'
4
+
5
+ module RubyGitCrypt
6
+ module Options
7
+ module Values
8
+ class Base < ImmutableStruct.new(:value)
9
+ def initialize(value)
10
+ super(value: value)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module RubyGitCrypt
6
+ module Options
7
+ module Values
8
+ class Boolean < Base
9
+ def resolve
10
+ return nil if @value.nil?
11
+ return @value if a_boolean?(@value)
12
+ return true if true_as_string?(@value)
13
+
14
+ false
15
+ end
16
+
17
+ def render
18
+ resolve&.to_s
19
+ end
20
+
21
+ private
22
+
23
+ def a_boolean?(value)
24
+ value.is_a?(TrueClass) || value.is_a?(FalseClass)
25
+ end
26
+
27
+ def true_as_string?(value)
28
+ value.respond_to?(:downcase) && value.downcase == 'true'
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ require_relative 'base'
6
+
7
+ module RubyGitCrypt
8
+ module Options
9
+ module Values
10
+ class Complex < Base
11
+ def resolve
12
+ @value
13
+ end
14
+
15
+ def render
16
+ @value.is_a?(::String) ? @value : JSON.generate(value)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'immutable-struct'
4
+
5
+ module RubyGitCrypt
6
+ module Options
7
+ module Values
8
+ class KeyValue < ImmutableStruct.new(:key, :value)
9
+ def initialize(key, value)
10
+ super(key: key, value: value)
11
+ end
12
+
13
+ def resolve
14
+ { key => value.resolve }
15
+ end
16
+
17
+ def render
18
+ "'#{key}=#{value.render}'"
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module RubyGitCrypt
6
+ module Options
7
+ module Values
8
+ class String < Base
9
+ def resolve
10
+ @value.to_s
11
+ end
12
+
13
+ alias render resolve
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'values/boolean'
4
+ require_relative 'values/string'
5
+ require_relative 'values/complex'
6
+ require_relative 'values/key_value'
7
+
8
+ module RubyGitCrypt
9
+ module Options
10
+ module Values
11
+ def self.boolean(value)
12
+ Boolean.new(value)
13
+ end
14
+
15
+ def self.string(value)
16
+ String.new(value)
17
+ end
18
+
19
+ def self.complex(value)
20
+ Complex.new(value)
21
+ end
22
+
23
+ def self.key_value(key, value)
24
+ KeyValue.new(key, value)
25
+ end
26
+
27
+ def self.resolve(type)
28
+ case type
29
+ when :string then Values::String
30
+ when :boolean then Values::Boolean
31
+ when :complex then Values::Complex
32
+ when :key_value then Values::KeyValue
33
+ else type
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'options/name'
4
+ require_relative 'options/types'
5
+ require_relative 'options/values'
6
+ require_relative 'options/definition'
7
+ require_relative 'options/factory'
8
+ require_relative 'options/sets'
9
+
10
+ module RubyGitCrypt
11
+ module Options
12
+ def self.name(name)
13
+ Name.new(name)
14
+ end
15
+
16
+ def self.definition(opts)
17
+ Definition.new(opts)
18
+ end
19
+
20
+ def self.types
21
+ Types
22
+ end
23
+
24
+ def self.values
25
+ Values
26
+ end
27
+ end
28
+ end
29
+
30
+ require_relative 'options/definitions'
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyGitCrypt
4
+ VERSION = '0.1.0.pre.1'
5
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'ruby_git_crypt/options'
4
+ require_relative 'ruby_git_crypt/version'
5
+ require_relative 'ruby_git_crypt/commands'
6
+ require 'logger'
7
+
8
+ module RubyGitCrypt
9
+ class << self
10
+ def configuration
11
+ @configuration ||= Configuration.new
12
+ end
13
+
14
+ def configure
15
+ yield(configuration)
16
+ end
17
+
18
+ def reset!
19
+ @configuration = nil
20
+ end
21
+ end
22
+
23
+ module ClassMethods
24
+ def status(parameters = {}, invocation_options = {})
25
+ exec(RubyGitCrypt::Commands::Status,
26
+ parameters, invocation_options)
27
+ end
28
+
29
+ private
30
+
31
+ def exec(command_class, parameters, invocation_options)
32
+ command_class.new.execute(parameters, invocation_options)
33
+ end
34
+ end
35
+
36
+ extend ClassMethods
37
+
38
+ def self.included(other)
39
+ other.extend(ClassMethods)
40
+ end
41
+
42
+ class Configuration
43
+ attr_accessor :binary, :logger, :options, :stdin, :stdout, :stderr
44
+
45
+ def default_logger
46
+ logger = Logger.new($stdout)
47
+ logger.level = Logger::INFO
48
+ logger
49
+ end
50
+
51
+ def default_options
52
+ Options::Factory.new(Options::DEFINITIONS)
53
+ end
54
+
55
+ def initialize
56
+ @binary = 'git-crypt'
57
+ @logger = default_logger
58
+ @options = default_options
59
+ @stdin = ''
60
+ @stdout = $stdout
61
+ @stderr = $stderr
62
+ end
63
+ end
64
+ end