kangaru 0.1.2 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 15146a85b29524ce8435963bbc25601017d72cafef5cf69331b920219bad4113
4
- data.tar.gz: de9a21f5cb27508169c1fec64b60f7a2aeacbb0beaac0b3fa1392288ea5f7728
3
+ metadata.gz: 14de853c7d43559d44b5dab8ca97090305697c8cb14245b9647b1f67d17036a6
4
+ data.tar.gz: 96572ecb84ae6cc4a74833d0456678bf66b8dcfbe701977ba6c920236cba5c64
5
5
  SHA512:
6
- metadata.gz: 03d7d75d0b7c98d7ea7cfa74390fe9bd16ad8d0c02ee7d9e5cc61499b8f545fb90cbf0b8a0361851088b59066f91c0ca24f429747c084d9984ededdd233c5363
7
- data.tar.gz: 9ec21c22c2f17b8943e546060fe872d08f43c38038970abdfdafb867eff1a7d134931069ae03eae832171ab280433bf236ca22635c3fa1c59d0bd76382dfa6c4
6
+ metadata.gz: ad440db45f269703c52939c80b0534b527c54e3649e15f2206af920818b2f8b5529c52a9127364a74b7f72d38fe56976ee5a6d8fe610585365a67bcb46b30176
7
+ data.tar.gz: 67ca725ea8b804a30a0ea4769a0203af75601e546dcfe56dc237f308bda356cc6029e5c01921064044188d955c667e0d74e643f0d52cf309ebecf04403cf157c
data/.rubocop.yml CHANGED
@@ -73,3 +73,5 @@ RSpec/NestedGroups:
73
73
  Enabled: false
74
74
  RSpec/SharedExamples:
75
75
  Enabled: false
76
+ RSpec/ExampleLength:
77
+ Max: 7
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- kangaru (0.1.2)
4
+ kangaru (0.2.1)
5
5
  colorize (~> 1.1)
6
6
  erb (~> 4.0)
7
7
  sequel (~> 5.72)
@@ -2,8 +2,12 @@ module Kangaru
2
2
  class Application
3
3
  extend Forwardable
4
4
 
5
+ class InvalidConfigError < StandardError; end
6
+
5
7
  attr_reader :paths, :namespace, :database
6
8
 
9
+ attr_accessor :config_path
10
+
7
11
  def initialize(source:, namespace:)
8
12
  @paths = Paths.new(source:)
9
13
  @namespace = namespace
@@ -20,11 +24,8 @@ module Kangaru
20
24
  @router ||= Router.new(namespace:)
21
25
  end
22
26
 
23
- # If called with no env, the config will be applied regardless of current
24
- # env. If multiple configure calls matching the current env are made, the
25
- # most recent calls will overwrite older changes.
26
- def configure(env = nil, &block)
27
- block.call(config) if current_env?(env)
27
+ def configure(&block)
28
+ block.call(config)
28
29
  end
29
30
 
30
31
  def configured?
@@ -34,7 +35,9 @@ module Kangaru
34
35
  def apply_config!
35
36
  raise "config already applied" if configured?
36
37
 
37
- config.import_external_config!
38
+ config.import!(config_path) unless config_path.nil?
39
+
40
+ validate_config!
38
41
 
39
42
  @database = setup_database!
40
43
  @configured = true
@@ -46,16 +49,15 @@ module Kangaru
46
49
  router.resolve(request)
47
50
  end
48
51
 
49
- def_delegators :paths, :view_path
52
+ def const_get(const)
53
+ return unless namespace.const_defined?(const)
50
54
 
51
- private
55
+ namespace.const_get(const)
56
+ end
52
57
 
53
- # Returns true if nil as this is represents all envs.
54
- def current_env?(env)
55
- return true if env.nil?
58
+ def_delegators :paths, :view_path
56
59
 
57
- Kangaru.env?(env)
58
- end
60
+ private
59
61
 
60
62
  def autoloader
61
63
  @autoloader ||= Zeitwerk::Loader.new.tap do |loader|
@@ -65,6 +67,14 @@ module Kangaru
65
67
  end
66
68
  end
67
69
 
70
+ def validate_config!
71
+ return if config.valid?
72
+
73
+ message = config.errors.map(&:full_message).join(", ")
74
+
75
+ raise InvalidConfigError, message
76
+ end
77
+
68
78
  def setup_database!
69
79
  return unless config.database.adaptor
70
80
 
@@ -22,6 +22,10 @@ module Kangaru
22
22
  def initialize(**attributes)
23
23
  attributes = self.class.defaults.merge(**attributes)
24
24
 
25
+ merge!(**attributes)
26
+ end
27
+
28
+ def merge!(**attributes)
25
29
  attributes.slice(*self.class.attributes).each do |attr, value|
26
30
  instance_variable_set(:"@#{attr}", value)
27
31
  end
@@ -3,18 +3,19 @@ module Kangaru
3
3
  module Configurable
4
4
  extend Concern
5
5
 
6
- using Patches::Constantise
6
+ using Patches::Inflections
7
7
 
8
8
  class_methods do
9
- def configurator_name
9
+ def configurator_key
10
10
  (name || raise("class name not set"))
11
- .gsub(/^(.*?)::/, "\\1::Configurators::")
12
- .concat("Configurator")
11
+ .gsub(/^.*::/, "")
12
+ .to_snakecase
13
+ .to_sym
13
14
  end
14
15
  end
15
16
 
16
17
  def config
17
- Kangaru.application!.config.for(self.class.configurator_name) ||
18
+ Kangaru.application!.config[self.class.configurator_key] ||
18
19
  raise("inferred configurator not set by application")
19
20
  end
20
21
  end
@@ -1,27 +1,38 @@
1
1
  module Kangaru
2
2
  class Config
3
+ using Patches::Symboliser
4
+
3
5
  attr_reader :configurators
4
6
 
5
7
  def initialize
6
8
  @configurators = set_configurators!
7
9
  end
8
10
 
11
+ def import!(path)
12
+ read_external_config(path).each do |key, config|
13
+ configurators[key]&.merge!(**config)
14
+ end
15
+ end
16
+
9
17
  def serialise
10
18
  configurators.transform_values(&:serialise)
11
19
  end
12
20
 
13
- def import_external_config!
14
- return unless external_config_exists?
21
+ def [](key)
22
+ configurators[key.to_sym]
23
+ end
15
24
 
16
- @external = Configurators::ExternalConfigurator
17
- .from_yaml_file(application.config_path)
25
+ def valid?
26
+ validate
27
+ errors.empty?
18
28
  end
19
29
 
20
- # Returns the configurator instance with the given class name.
21
- def for(configurator_name)
22
- configurators.values.find do |configurator|
23
- configurator.class.name == configurator_name # rubocop:disable Style
24
- end
30
+ def validate
31
+ configurators.each_value(&:validate)
32
+ end
33
+
34
+ def errors
35
+ configurators.values.flat_map(&:errors)
25
36
  end
26
37
 
27
38
  private
@@ -38,8 +49,10 @@ module Kangaru
38
49
  end
39
50
  end
40
51
 
41
- def external_config_exists?
42
- application.config_path && File.exist?(application.config_path)
52
+ def read_external_config(path)
53
+ return {} unless File.exist?(path)
54
+
55
+ YAML.load_file(path)&.symbolise || {}
43
56
  end
44
57
  end
45
58
  end
@@ -0,0 +1,21 @@
1
+ module Kangaru
2
+ class Configurator
3
+ include Concerns::AttributesConcern
4
+ include Concerns::Validatable
5
+
6
+ using Patches::Inflections
7
+
8
+ def self.key
9
+ to_s.gsub(/^.*::(?!.*::)/, "")
10
+ .delete_suffix("Configurator")
11
+ .to_snakecase
12
+ .to_sym
13
+ end
14
+
15
+ def serialise
16
+ self.class.attributes.to_h do |setting|
17
+ [setting, send(setting)]
18
+ end.compact
19
+ end
20
+ end
21
+ end
@@ -1,12 +1,21 @@
1
1
  module Kangaru
2
2
  module Configurators
3
- # These are not set as accessors by Config instances as they are abstract.
4
- BASE_CONFIGURATORS = [Configurator, OpenConfigurator].freeze
5
-
6
3
  def self.classes
7
- constants.map { |constant| const_get(constant) }
8
- .select { |constant| constant.is_a?(Class) }
9
- .reject { |constant| BASE_CONFIGURATORS.include?(constant) }
4
+ load_classes(self) + load_classes(application_configurators)
5
+ end
6
+
7
+ def self.application_configurators
8
+ Kangaru.application&.const_get(:Configurators)
10
9
  end
10
+
11
+ def self.load_classes(root)
12
+ return [] if root.nil?
13
+
14
+ root.constants.map { |const| root.const_get(const) }
15
+ .select { |const| const.is_a?(Class) }
16
+ end
17
+
18
+ private_class_method :application_configurators
19
+ private_class_method :load_classes
11
20
  end
12
21
  end
@@ -6,7 +6,7 @@ module Kangaru
6
6
  Kangaru.application = Application.new(source:, namespace:)
7
7
  Kangaru.eager_load(Initialisers)
8
8
 
9
- namespace.extend InjectedMethods
9
+ namespace.extend Interface
10
10
  end
11
11
  end
12
12
  end
@@ -0,0 +1,39 @@
1
+ module Kangaru
2
+ module Interface
3
+ def run!(*argv)
4
+ Kangaru.application!.run!(*argv)
5
+ end
6
+
7
+ def config
8
+ Kangaru.application!.config
9
+ end
10
+
11
+ def configure(env: nil, &)
12
+ return unless env_applies?(env)
13
+
14
+ Kangaru.application!.configure(&)
15
+ end
16
+
17
+ def config_path(path, env: nil)
18
+ return unless env_applies?(env)
19
+
20
+ Kangaru.application!.config_path = path
21
+ end
22
+
23
+ def apply_config!
24
+ Kangaru.application!.apply_config!
25
+ end
26
+
27
+ def database
28
+ Kangaru.application!.database
29
+ end
30
+
31
+ private
32
+
33
+ def env_applies?(env)
34
+ return true if env.nil?
35
+
36
+ Kangaru.env?(env)
37
+ end
38
+ end
39
+ end
@@ -1,3 +1,3 @@
1
1
  module Kangaru
2
- VERSION = "0.1.2".freeze
2
+ VERSION = "0.2.1".freeze
3
3
  end
@@ -2,15 +2,21 @@ module Kangaru
2
2
  class Application
3
3
  extend Forwardable
4
4
 
5
+ class InvalidConfigError < StandardError
6
+ end
7
+
5
8
  attr_reader paths: Paths
6
9
  attr_reader namespace: Module
7
- attr_reader config: Config
8
10
  attr_reader database: Database?
11
+
12
+ attr_accessor config_path: String
13
+
14
+ attr_reader config: Config
9
15
  attr_reader router: Router
10
16
 
11
17
  def initialize: (source: String, namespace: Module) -> void
12
18
 
13
- def configure: (?Symbol?) { (Config) -> void } -> void
19
+ def configure: { (Config) -> void } -> void
14
20
 
15
21
  def configured?: -> bool
16
22
 
@@ -18,6 +24,9 @@ module Kangaru
18
24
 
19
25
  def run!: (*String) -> void
20
26
 
27
+ def const_get: (String | Symbol) -> Module?
28
+ | (String | Symbol) -> Class?
29
+
21
30
  # Delegated to paths
22
31
  def view_path: (*String, ?ext: Symbol?) -> Pathname
23
32
 
@@ -25,10 +34,10 @@ module Kangaru
25
34
 
26
35
  @configured: bool
27
36
 
28
- def current_env?: (Symbol?) -> bool
29
-
30
37
  attr_reader autoloader: Zeitwerk::Loader
31
38
 
39
+ def validate_config!: -> void
40
+
32
41
  def setup_database!: -> Database?
33
42
  end
34
43
  end
@@ -20,6 +20,8 @@ module Kangaru
20
20
  def instance_methods: -> Array[Symbol]
21
21
 
22
22
  def initialize: (**untyped) -> void
23
+
24
+ def merge!: (**untyped) -> void
23
25
  end
24
26
  end
25
27
  end
@@ -5,11 +5,11 @@ module Kangaru
5
5
  extend ClassMethods
6
6
 
7
7
  module ClassMethods
8
- def configurator_name: -> String
8
+ def configurator_key: -> Symbol
9
9
  end
10
10
 
11
11
  def name: -> String
12
- def config: [C < Configurators::Configurator] -> C
12
+ def config: -> untyped
13
13
  end
14
14
  end
15
15
  end
@@ -1,27 +1,29 @@
1
1
  module Kangaru
2
2
  class Config
3
- type configurator = Configurators::Configurator
4
-
5
- attr_reader configurators: Hash[Symbol, configurator]
3
+ attr_reader configurators: Hash[Symbol, Configurator]
6
4
 
7
5
  def initialize: -> void
8
6
 
7
+ def import!: (String) -> void
8
+
9
9
  def serialise: -> Hash[Symbol, Hash[Symbol, untyped]]
10
10
 
11
- def import_external_config!: -> void
11
+ def []: (Symbol) -> Configurator?
12
+
13
+ def valid?: -> bool
14
+
15
+ def validate: -> void
12
16
 
13
- def for: (String) -> untyped
17
+ def errors: -> Array[Validation::Error]
14
18
 
15
- # Configurators
16
- attr_reader application: Configurators::ApplicationConfigurator
17
- attr_reader database: Configurators::DatabaseConfigurator
18
- attr_reader external: Configurators::ExternalConfigurator
19
- attr_reader request: Configurators::RequestConfigurator
19
+ # Native Configurators
20
+ attr_reader database: Configurators::DatabaseConfigurator
21
+ attr_reader request: Configurators::RequestConfigurator
20
22
 
21
23
  private
22
24
 
23
- def set_configurators!: -> Hash[Symbol, configurator]
25
+ def set_configurators!: -> Hash[Symbol, Configurator]
24
26
 
25
- def external_config_exists?: -> bool
27
+ def read_external_config: (String) -> Hash[Symbol, untyped]
26
28
  end
27
29
  end
@@ -0,0 +1,15 @@
1
+ module Kangaru
2
+ class Configurator
3
+ include Concerns::AttributesConcern
4
+ extend Concerns::AttributesConcern::ClassMethods
5
+
6
+ include Concerns::Validatable
7
+ extend Concerns::Validatable::ClassMethods
8
+
9
+ def self.key: -> Symbol
10
+
11
+ def self.name: -> String
12
+
13
+ def serialise: -> Hash[Symbol, untyped]
14
+ end
15
+ end
@@ -1,7 +1,11 @@
1
1
  module Kangaru
2
2
  module Configurators
3
- BASE_CONFIGURATORS: Array[singleton(Configurator)]
4
-
5
3
  def self.classes: -> Array[singleton(Configurator)]
4
+
5
+ private
6
+
7
+ def self.application_configurators: -> Module?
8
+
9
+ def self.load_classes: (Module?) -> Array[singleton(Configurator)]
6
10
  end
7
11
  end
@@ -1,9 +1,5 @@
1
1
  module Kangaru
2
2
  module Initialiser
3
- module InjectedMethods
4
- include Kangaru::_ApplicationMethods
5
- end
6
-
7
3
  def self.extended: (Module) -> void
8
4
  end
9
5
  end
@@ -0,0 +1,21 @@
1
+ module Kangaru
2
+ module Interface
3
+ type env = Symbol?
4
+
5
+ def run!: (*String) -> void
6
+
7
+ def config: -> Config
8
+
9
+ def configure: (?env: env) { (Config) -> void } -> void
10
+
11
+ def apply_config!: -> void
12
+
13
+ def config_path: (String, ?env: env) -> void
14
+
15
+ def database: -> Database?
16
+
17
+ private
18
+
19
+ def env_applies?: (Symbol?) -> bool
20
+ end
21
+ end
data/sig/kangaru.rbs CHANGED
@@ -21,9 +21,4 @@ module Kangaru
21
21
 
22
22
  def test?: -> bool
23
23
  end
24
-
25
- # Included in target applications that extend Kangaru::Initialiser.
26
- interface _ApplicationMethods
27
- include InjectedMethods::_InjectedMethods
28
- end
29
24
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kangaru
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Welham
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-11-08 00:00:00.000000000 Z
11
+ date: 2023-11-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize
@@ -107,12 +107,9 @@ files:
107
107
  - lib/kangaru/concerns/configurable.rb
108
108
  - lib/kangaru/concerns/validatable.rb
109
109
  - lib/kangaru/config.rb
110
+ - lib/kangaru/configurator.rb
110
111
  - lib/kangaru/configurators.rb
111
- - lib/kangaru/configurators/application_configurator.rb
112
- - lib/kangaru/configurators/configurator.rb
113
112
  - lib/kangaru/configurators/database_configurator.rb
114
- - lib/kangaru/configurators/external_configurator.rb
115
- - lib/kangaru/configurators/open_configurator.rb
116
113
  - lib/kangaru/configurators/request_configurator.rb
117
114
  - lib/kangaru/controller.rb
118
115
  - lib/kangaru/database.rb
@@ -130,7 +127,7 @@ files:
130
127
  - lib/kangaru/initialisers/rspec.rb
131
128
  - lib/kangaru/initialisers/rspec/kangaru_helper.rb
132
129
  - lib/kangaru/initialisers/rspec/request_helper.rb
133
- - lib/kangaru/injected_methods.rb
130
+ - lib/kangaru/interface.rb
134
131
  - lib/kangaru/model.rb
135
132
  - lib/kangaru/patches/constantise.rb
136
133
  - lib/kangaru/patches/inflections.rb
@@ -159,12 +156,9 @@ files:
159
156
  - sig/kangaru/concerns/configurable.rbs
160
157
  - sig/kangaru/concerns/validatable.rbs
161
158
  - sig/kangaru/config.rbs
159
+ - sig/kangaru/configurator.rbs
162
160
  - sig/kangaru/configurators.rbs
163
- - sig/kangaru/configurators/application_configurator.rbs
164
- - sig/kangaru/configurators/configurator.rbs
165
161
  - sig/kangaru/configurators/database_configurator.rbs
166
- - sig/kangaru/configurators/external_configurator.rbs
167
- - sig/kangaru/configurators/open_configurator.rbs
168
162
  - sig/kangaru/configurators/request_configurator.rbs
169
163
  - sig/kangaru/controller.rbs
170
164
  - sig/kangaru/database.rbs
@@ -180,7 +174,7 @@ files:
180
174
  - sig/kangaru/inflectors/tokeniser.rbs
181
175
  - sig/kangaru/initialiser.rbs
182
176
  - sig/kangaru/initialisers/rspec.rbs
183
- - sig/kangaru/injected_methods.rbs
177
+ - sig/kangaru/interface.rbs
184
178
  - sig/kangaru/model.rbs
185
179
  - sig/kangaru/patches/constantise.rbs
186
180
  - sig/kangaru/patches/inflections.rbs
@@ -1,7 +0,0 @@
1
- module Kangaru
2
- module Configurators
3
- class ApplicationConfigurator < Configurator
4
- attr_accessor :config_path
5
- end
6
- end
7
- end
@@ -1,22 +0,0 @@
1
- module Kangaru
2
- module Configurators
3
- class Configurator
4
- include Concerns::AttributesConcern
5
-
6
- using Patches::Inflections
7
-
8
- def self.key
9
- to_s.gsub(/^.*::(?!.*::)/, "")
10
- .delete_suffix("Configurator")
11
- .to_snakecase
12
- .to_sym
13
- end
14
-
15
- def serialise
16
- self.class.attributes.to_h do |setting|
17
- [setting, send(setting)]
18
- end.compact
19
- end
20
- end
21
- end
22
- end
@@ -1,6 +0,0 @@
1
- module Kangaru
2
- module Configurators
3
- class ExternalConfigurator < OpenConfigurator
4
- end
5
- end
6
- end
@@ -1,33 +0,0 @@
1
- # Similar to a standard configurator, except on initialisation, it will set
2
- # accessors for every attribute specified. This means that the super call will
3
- # lead to each value being set as if the accessor was defined in the class.
4
- module Kangaru
5
- module Configurators
6
- class OpenConfigurator < Configurator
7
- using Patches::Symboliser
8
-
9
- def initialize(**)
10
- set_accessors!(**)
11
-
12
- super
13
- end
14
-
15
- # Import contents of a yaml file
16
- def self.from_yaml_file(path)
17
- raise "path does not exist" unless File.exist?(path)
18
-
19
- attributes = YAML.load_file(path).symbolise
20
-
21
- new(**attributes)
22
- end
23
-
24
- private
25
-
26
- def set_accessors!(**attributes)
27
- attributes.each_key do |key|
28
- self.class.class_eval { attr_accessor key }
29
- end
30
- end
31
- end
32
- end
33
- end
@@ -1,23 +0,0 @@
1
- module Kangaru
2
- module InjectedMethods
3
- def run!(*argv)
4
- Kangaru.application!.run!(*argv)
5
- end
6
-
7
- def config
8
- Kangaru.application!.config
9
- end
10
-
11
- def configure(env = nil, &)
12
- Kangaru.application!.configure(env, &)
13
- end
14
-
15
- def apply_config!
16
- Kangaru.application!.apply_config!
17
- end
18
-
19
- def database
20
- Kangaru.application!.database
21
- end
22
- end
23
- end
@@ -1,7 +0,0 @@
1
- module Kangaru
2
- module Configurators
3
- class ApplicationConfigurator < Configurator
4
- attr_accessor config_path: String
5
- end
6
- end
7
- end
@@ -1,14 +0,0 @@
1
- module Kangaru
2
- module Configurators
3
- class Configurator
4
- include Concerns::AttributesConcern
5
- extend Concerns::AttributesConcern::ClassMethods
6
-
7
- def self.key: -> Symbol
8
-
9
- def self.name: -> String
10
-
11
- def serialise: -> Hash[Symbol, untyped]
12
- end
13
- end
14
- end
@@ -1,6 +0,0 @@
1
- module Kangaru
2
- module Configurators
3
- class ExternalConfigurator < OpenConfigurator
4
- end
5
- end
6
- end
@@ -1,11 +0,0 @@
1
- module Kangaru
2
- module Configurators
3
- class OpenConfigurator < Configurator
4
- def self.from_yaml_file: (String) -> instance
5
-
6
- private
7
-
8
- def set_accessors!: (**untyped) -> void
9
- end
10
- end
11
- end
@@ -1,17 +0,0 @@
1
- module Kangaru
2
- module InjectedMethods
3
- interface _InjectedMethods
4
- def run!: (*String) -> void
5
-
6
- def config: -> Config
7
-
8
- def configure: (?Symbol?) { (Config) -> void } -> void
9
-
10
- def apply_config!: -> void
11
-
12
- def database: -> Database?
13
- end
14
-
15
- include _InjectedMethods
16
- end
17
- end