kangaru 0.1.2 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
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