piko-lite-box 0.0.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.
Files changed (99) hide show
  1. checksums.yaml +7 -0
  2. data/hanami-3.0.1/CHANGELOG.md +1701 -0
  3. data/hanami-3.0.1/LICENSE +20 -0
  4. data/hanami-3.0.1/README.md +89 -0
  5. data/hanami-3.0.1/hanami.gemspec +49 -0
  6. data/hanami-3.0.1/lib/hanami/app.rb +197 -0
  7. data/hanami-3.0.1/lib/hanami/boot.rb +5 -0
  8. data/hanami-3.0.1/lib/hanami/config/actions/content_security_policy.rb +140 -0
  9. data/hanami-3.0.1/lib/hanami/config/actions/cookies.rb +57 -0
  10. data/hanami-3.0.1/lib/hanami/config/actions/sessions.rb +83 -0
  11. data/hanami-3.0.1/lib/hanami/config/actions.rb +189 -0
  12. data/hanami-3.0.1/lib/hanami/config/assets.rb +84 -0
  13. data/hanami-3.0.1/lib/hanami/config/console.rb +79 -0
  14. data/hanami-3.0.1/lib/hanami/config/db.rb +35 -0
  15. data/hanami-3.0.1/lib/hanami/config/i18n.rb +138 -0
  16. data/hanami-3.0.1/lib/hanami/config/logger.rb +207 -0
  17. data/hanami-3.0.1/lib/hanami/config/null_config.rb +17 -0
  18. data/hanami-3.0.1/lib/hanami/config/router.rb +48 -0
  19. data/hanami-3.0.1/lib/hanami/config/views.rb +103 -0
  20. data/hanami-3.0.1/lib/hanami/config.rb +564 -0
  21. data/hanami-3.0.1/lib/hanami/constants.rb +62 -0
  22. data/hanami-3.0.1/lib/hanami/env.rb +52 -0
  23. data/hanami-3.0.1/lib/hanami/errors.rb +41 -0
  24. data/hanami-3.0.1/lib/hanami/extensions/action/i18n_helper.rb +64 -0
  25. data/hanami-3.0.1/lib/hanami/extensions/action/name_inferrer.rb +34 -0
  26. data/hanami-3.0.1/lib/hanami/extensions/action/slice_configured_action.rb +190 -0
  27. data/hanami-3.0.1/lib/hanami/extensions/action.rb +147 -0
  28. data/hanami-3.0.1/lib/hanami/extensions/db/repo.rb +108 -0
  29. data/hanami-3.0.1/lib/hanami/extensions/mailer/slice_configured_mailer.rb +134 -0
  30. data/hanami-3.0.1/lib/hanami/extensions/mailer.rb +28 -0
  31. data/hanami-3.0.1/lib/hanami/extensions/operation/slice_configured_db_operation.rb +90 -0
  32. data/hanami-3.0.1/lib/hanami/extensions/operation.rb +33 -0
  33. data/hanami-3.0.1/lib/hanami/extensions/router/errors.rb +58 -0
  34. data/hanami-3.0.1/lib/hanami/extensions/view/context.rb +298 -0
  35. data/hanami-3.0.1/lib/hanami/extensions/view/part.rb +92 -0
  36. data/hanami-3.0.1/lib/hanami/extensions/view/scope.rb +36 -0
  37. data/hanami-3.0.1/lib/hanami/extensions/view/slice_configured_context.rb +73 -0
  38. data/hanami-3.0.1/lib/hanami/extensions/view/slice_configured_helpers.rb +55 -0
  39. data/hanami-3.0.1/lib/hanami/extensions/view/slice_configured_part.rb +73 -0
  40. data/hanami-3.0.1/lib/hanami/extensions/view/slice_configured_view.rb +243 -0
  41. data/hanami-3.0.1/lib/hanami/extensions/view/standard_helpers.rb +26 -0
  42. data/hanami-3.0.1/lib/hanami/extensions/view.rb +38 -0
  43. data/hanami-3.0.1/lib/hanami/extensions.rb +30 -0
  44. data/hanami-3.0.1/lib/hanami/helpers/assets_helper.rb +804 -0
  45. data/hanami-3.0.1/lib/hanami/helpers/form_helper/form_builder.rb +1389 -0
  46. data/hanami-3.0.1/lib/hanami/helpers/form_helper/values.rb +75 -0
  47. data/hanami-3.0.1/lib/hanami/helpers/form_helper.rb +213 -0
  48. data/hanami-3.0.1/lib/hanami/helpers/i18n_helper.rb +241 -0
  49. data/hanami-3.0.1/lib/hanami/logger/rack_formatter.rb +73 -0
  50. data/hanami-3.0.1/lib/hanami/logger/sql_formatter.rb +80 -0
  51. data/hanami-3.0.1/lib/hanami/logger/sql_logger.rb +48 -0
  52. data/hanami-3.0.1/lib/hanami/middleware/assets.rb +21 -0
  53. data/hanami-3.0.1/lib/hanami/middleware/content_security_policy_nonce.rb +53 -0
  54. data/hanami-3.0.1/lib/hanami/middleware/public_errors_app.rb +75 -0
  55. data/hanami-3.0.1/lib/hanami/middleware/render_errors.rb +90 -0
  56. data/hanami-3.0.1/lib/hanami/port.rb +45 -0
  57. data/hanami-3.0.1/lib/hanami/prepare.rb +5 -0
  58. data/hanami-3.0.1/lib/hanami/provider/source.rb +16 -0
  59. data/hanami-3.0.1/lib/hanami/provider_registrar.rb +28 -0
  60. data/hanami-3.0.1/lib/hanami/providers/assets.rb +28 -0
  61. data/hanami-3.0.1/lib/hanami/providers/db/adapter.rb +75 -0
  62. data/hanami-3.0.1/lib/hanami/providers/db/adapters.rb +66 -0
  63. data/hanami-3.0.1/lib/hanami/providers/db/config.rb +44 -0
  64. data/hanami-3.0.1/lib/hanami/providers/db/gateway.rb +87 -0
  65. data/hanami-3.0.1/lib/hanami/providers/db/sql_adapter.rb +100 -0
  66. data/hanami-3.0.1/lib/hanami/providers/db.rb +325 -0
  67. data/hanami-3.0.1/lib/hanami/providers/db_logging.rb +19 -0
  68. data/hanami-3.0.1/lib/hanami/providers/i18n/backend.rb +373 -0
  69. data/hanami-3.0.1/lib/hanami/providers/i18n/locale/en.yml +57 -0
  70. data/hanami-3.0.1/lib/hanami/providers/i18n.rb +114 -0
  71. data/hanami-3.0.1/lib/hanami/providers/inflector.rb +17 -0
  72. data/hanami-3.0.1/lib/hanami/providers/logger.rb +41 -0
  73. data/hanami-3.0.1/lib/hanami/providers/mailers.rb +101 -0
  74. data/hanami-3.0.1/lib/hanami/providers/rack.rb +47 -0
  75. data/hanami-3.0.1/lib/hanami/providers/relations.rb +31 -0
  76. data/hanami-3.0.1/lib/hanami/providers/routes.rb +29 -0
  77. data/hanami-3.0.1/lib/hanami/rake_tasks.rb +54 -0
  78. data/hanami-3.0.1/lib/hanami/routes.rb +146 -0
  79. data/hanami-3.0.1/lib/hanami/settings/composite_store.rb +53 -0
  80. data/hanami-3.0.1/lib/hanami/settings/env_store.rb +32 -0
  81. data/hanami-3.0.1/lib/hanami/settings.rb +234 -0
  82. data/hanami-3.0.1/lib/hanami/setup.rb +6 -0
  83. data/hanami-3.0.1/lib/hanami/slice/router.rb +280 -0
  84. data/hanami-3.0.1/lib/hanami/slice/routes_helper.rb +37 -0
  85. data/hanami-3.0.1/lib/hanami/slice/routing/middleware/stack.rb +216 -0
  86. data/hanami-3.0.1/lib/hanami/slice/routing/resolver.rb +88 -0
  87. data/hanami-3.0.1/lib/hanami/slice/view_name_inferrer.rb +63 -0
  88. data/hanami-3.0.1/lib/hanami/slice.rb +1239 -0
  89. data/hanami-3.0.1/lib/hanami/slice_configurable.rb +72 -0
  90. data/hanami-3.0.1/lib/hanami/slice_name.rb +111 -0
  91. data/hanami-3.0.1/lib/hanami/slice_registrar.rb +215 -0
  92. data/hanami-3.0.1/lib/hanami/universal_logger.rb +250 -0
  93. data/hanami-3.0.1/lib/hanami/version.rb +45 -0
  94. data/hanami-3.0.1/lib/hanami/web/rack_logger.rb +126 -0
  95. data/hanami-3.0.1/lib/hanami/web/welcome.html.erb +584 -0
  96. data/hanami-3.0.1/lib/hanami/web/welcome.rb +46 -0
  97. data/hanami-3.0.1/lib/hanami.rb +276 -0
  98. data/piko-lite-box.gemspec +11 -0
  99. metadata +137 -0
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanami
4
+ # @api private
5
+ module Providers
6
+ # Provider source to register Rack integration components in Hanami slices.
7
+ #
8
+ # @see Hanami::Providers::Logger
9
+ # @see Hanami::Web::RackLogger
10
+ # @see https://github.com/rack/rack
11
+ # @see https://dry-rb.org/gems/dry-monitor/
12
+ #
13
+ # @api private
14
+ # @since 2.0.0
15
+ class Rack < Hanami::Provider::Source
16
+ # @api private
17
+ def prepare
18
+ Dry::Monitor.load_extensions(:rack)
19
+
20
+ # Explicitly register the Rack middleware events on our notifications bus. The Dry::Monitor
21
+ # rack extension (activated above) does register these globally, but if the notifications
22
+ # bus has been used before this provider loads, then it will have created its own separate
23
+ # local copy of all registered events as of that moment in time, which will not be included
24
+ # in the Rack events globally registered above.
25
+ notifications = target["notifications"]
26
+ notifications.register_event(Dry::Monitor::Rack::Middleware::REQUEST_START)
27
+ notifications.register_event(Dry::Monitor::Rack::Middleware::REQUEST_STOP)
28
+ notifications.register_event(Dry::Monitor::Rack::Middleware::REQUEST_ERROR)
29
+ end
30
+
31
+ # @api private
32
+ def start
33
+ slice.start :logger
34
+
35
+ monitor_middleware = Dry::Monitor::Rack::Middleware.new(
36
+ target["notifications"],
37
+ clock: Dry::Monitor::Clock.new(unit: :microsecond)
38
+ )
39
+
40
+ rack_logger = Hanami::Web::RackLogger.new(target[:logger], env: slice.container.env)
41
+ rack_logger.attach(monitor_middleware)
42
+
43
+ register "monitor", monitor_middleware
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanami
4
+ module Providers
5
+ # @api private
6
+ # @since 2.2.0
7
+ class Relations < Hanami::Provider::Source
8
+ def start
9
+ start_and_import_parent_relations and return if slice.parent && slice.config.db.import_from_parent
10
+
11
+ slice.start :db
12
+
13
+ register_relations target["db.rom"]
14
+ end
15
+
16
+ private
17
+
18
+ def register_relations(rom)
19
+ rom.relations.each do |name, _|
20
+ register name, rom.relations[name]
21
+ end
22
+ end
23
+
24
+ def start_and_import_parent_relations
25
+ slice.parent.start :relations
26
+
27
+ register_relations slice.parent["db.rom"]
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanami
4
+ # @api private
5
+ module Providers
6
+ # Provider source to register routes helper component in Hanami slices.
7
+ #
8
+ # @see Hanami::Slice::RoutesHelper
9
+ #
10
+ # @api private
11
+ # @since 2.0.0
12
+ class Routes < Hanami::Provider::Source
13
+ # @api private
14
+ def prepare
15
+ require "hanami/slice/routes_helper"
16
+ end
17
+
18
+ # @api private
19
+ def start
20
+ # Register a lazy instance of RoutesHelper to ensure we don't load prematurely load the
21
+ # router during the process of booting. This ensures the router's resolver can run strict
22
+ # action key checks once when it runs on a fully booted slice.
23
+ register :routes do
24
+ Hanami::Slice::RoutesHelper.new(slice.router)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "hanami/cli"
4
+
5
+ Hanami::CLI::RakeTasks.register_tasks do
6
+ desc "Load the app environment"
7
+ task :environment do
8
+ require "hanami/prepare"
9
+ end
10
+
11
+ # Ruby ecosystem compatibility
12
+ #
13
+ # Most of the hosting SaaS automatic tasks are designed after Ruby on Rails.
14
+ # They expect the following Rake tasks to be present:
15
+ #
16
+ # * db:migrate
17
+ # * assets:precompile
18
+ #
19
+ # See https://github.com/heroku/heroku-buildpack-ruby/issues/442
20
+ #
21
+ # ===
22
+ #
23
+ # These Rake tasks are **NOT** listed when someone runs `rake -T`, because we
24
+ # want to encourage developers to use `hanami` CLI commands.
25
+ #
26
+ # In order to migrate the database or compile assets a developer should use:
27
+ #
28
+ # * hanami db migrate
29
+ # * hanami assets compile
30
+ #
31
+ # This is the preferred way to run Hanami command line tasks.
32
+ # Please use them when you're in control of your deployment environment.
33
+ #
34
+ # If you're not in control and your deployment requires these "standard"
35
+ # Rake tasks, they are here only to solve this specific problem.
36
+
37
+ if Hanami.bundled?("hanami-db")
38
+ namespace :db do
39
+ task :migrate do
40
+ Hanami::CLI::Commands::App::DB::Migrate.new.call
41
+ end
42
+ end
43
+ end
44
+
45
+ if Hanami.bundled?("hanami-assets")
46
+ namespace :assets do
47
+ task :precompile do
48
+ Hanami::CLI::Commands::App::Assets::Compile.new.call
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ Hanami::CLI::RakeTasks.install_tasks
@@ -0,0 +1,146 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "constants"
4
+ require_relative "errors"
5
+ require_relative "slice/router"
6
+
7
+ module Hanami
8
+ # App routes
9
+ #
10
+ # Users are expected to inherit from this class to define their app
11
+ # routes.
12
+ #
13
+ # @example
14
+ # # config/routes.rb
15
+ # # frozen_string_literal: true
16
+ #
17
+ # require "hanami/routes"
18
+ #
19
+ # module MyApp
20
+ # class Routes < Hanami::Routes
21
+ # root to: "home.show"
22
+ # end
23
+ # end
24
+ #
25
+ # See {Hanami::Slice::Router} for the syntax allowed within the `define` block.
26
+ #
27
+ # @see Hanami::Slice::Router
28
+ # @since 2.0.0
29
+ class Routes
30
+ # Error raised when no action could be found in an app or slice container for the key given in a
31
+ # routes file.
32
+ #
33
+ # @api public
34
+ # @since 2.0.0
35
+ class MissingActionError < Hanami::Error
36
+ # @api private
37
+ def initialize(action_key, slice)
38
+ action_path = action_key.gsub(CONTAINER_KEY_DELIMITER, PATH_DELIMITER)
39
+ action_constant = slice.inflector.camelize(
40
+ slice.inflector.underscore(slice.namespace.to_s) + PATH_DELIMITER + action_path
41
+ )
42
+ action_file_path = slice.relative_source_path.join(action_path).to_s.concat(RB_EXT)
43
+
44
+ super(<<~MSG)
45
+ Could not find action with key #{action_key.inspect} in #{slice}
46
+
47
+ To fix this, define the action class #{action_constant} in #{action_file_path}
48
+ MSG
49
+ end
50
+ end
51
+
52
+ # Error raised when a given routes endpoint does not implement the `#call` interface required
53
+ # for Rack.
54
+ #
55
+ # @api public
56
+ # @since 2.0.0
57
+ class NotCallableEndpointError < Hanami::Error
58
+ # @api private
59
+ def initialize(endpoint)
60
+ super("#{endpoint.inspect} is not compatible with Rack. Please make sure it implements #call.")
61
+ end
62
+ end
63
+
64
+ # Wrapper class for the (otherwise opaque) proc returned from {.routes}, adding an `#empty?`
65
+ # method that returns true if no routes were defined.
66
+ #
67
+ # This is useful when needing to determine behaviour based on the presence of user-defined
68
+ # routes, such as determining whether to show the Hanami welcome page in {Slice#load_router}.
69
+ #
70
+ # @api private
71
+ # @since 2.1.0
72
+ class RoutesProc < DelegateClass(Proc)
73
+ # @api private
74
+ # @since 2.1.0
75
+ def self.empty
76
+ new(proc {}, empty: true)
77
+ end
78
+
79
+ # @api private
80
+ # @since 2.1.0
81
+ def initialize(proc, empty: false)
82
+ @empty = empty
83
+ super(proc)
84
+ end
85
+
86
+ # @api private
87
+ # @since 2.1.0
88
+ def empty?
89
+ !!@empty
90
+ end
91
+ end
92
+
93
+ # @api private
94
+ def self.routes
95
+ @routes ||= build_routes
96
+ end
97
+
98
+ class << self
99
+ # @api private
100
+ def build_routes(definitions = self.definitions)
101
+ return RoutesProc.empty if definitions.empty?
102
+
103
+ routes_proc = proc do
104
+ definitions.each do |(name, args, kwargs, block)|
105
+ if block
106
+ public_send(name, *args, **kwargs, &block)
107
+ else
108
+ public_send(name, *args, **kwargs)
109
+ end
110
+ end
111
+ end
112
+
113
+ RoutesProc.new(routes_proc)
114
+ end
115
+
116
+ # @api private
117
+ def definitions
118
+ @definitions ||= []
119
+ end
120
+
121
+ private
122
+
123
+ # @api private
124
+ def supported_methods
125
+ @supported_methods ||= Slice::Router.public_instance_methods
126
+ end
127
+
128
+ # @api private
129
+ def respond_to_missing?(name, include_private = false)
130
+ supported_methods.include?(name) || super
131
+ end
132
+
133
+ # Capture all method calls that are supported by the router DSL
134
+ # so that it can be evaluated lazily during configuration/boot
135
+ # process
136
+ #
137
+ # @api private
138
+ def method_missing(name, *args, **kwargs, &block)
139
+ return super unless respond_to?(name)
140
+
141
+ definitions << [name, args, kwargs, block]
142
+ self
143
+ end
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/core/constants"
4
+
5
+ module Hanami
6
+ class Settings
7
+ # A settings store that chains multiple stores with fallback resolution.
8
+ #
9
+ # Each store is tried in order. The first store to return a value wins.
10
+ # Stores must implement `#fetch` with the same signature as `Hash#fetch`.
11
+ #
12
+ # @example
13
+ # # config/app.rb
14
+ # config.settings_store = Hanami::Settings::CompositeStore.new(
15
+ # Hanami::Settings::EnvStore.new,
16
+ # MyCustomStore.new
17
+ # )
18
+ #
19
+ # @api public
20
+ # @since 3.0.0
21
+ class CompositeStore
22
+ # @api private
23
+ Undefined = Dry::Core::Constants::Undefined
24
+
25
+ # @param stores [Array<#fetch>] ordered list of stores to query
26
+ def initialize(*stores)
27
+ @stores = stores
28
+ end
29
+
30
+ # Fetches a value by trying each store in order.
31
+ #
32
+ # @param name [String, Symbol] the setting name
33
+ # @param args [Array] optional default value
34
+ # @yield [name] optional block for default value
35
+ # @return [Object] the setting value
36
+ # @raise [KeyError] if no store has the key and no default is given
37
+ #
38
+ # @api public
39
+ # @since 3.0.0
40
+ def fetch(name, *args, &block)
41
+ @stores.each do |store|
42
+ value = store.fetch(name, Undefined)
43
+ return value unless value.equal?(Undefined)
44
+ end
45
+
46
+ return args.first unless args.empty?
47
+ return yield(name) if block
48
+
49
+ raise KeyError, "key not found: #{name.inspect}"
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/core/constants"
4
+
5
+ module Hanami
6
+ class Settings
7
+ # The default store for {Hanami::Settings}, loading setting values from `ENV`.
8
+ #
9
+ # If your app loads the dotenv gem, then `ENV` will also be populated from various `.env` files when
10
+ # you subclass `Hanami::App`.
11
+ #
12
+ # @since 2.0.0
13
+ # @api private
14
+ class EnvStore
15
+ NO_ARG = Object.new.freeze
16
+
17
+ attr_reader :store, :hanami_env
18
+
19
+ def initialize(store: ENV, hanami_env: Hanami.env)
20
+ @store = store
21
+ @hanami_env = hanami_env
22
+ end
23
+
24
+ def fetch(name, default_value = NO_ARG, &block)
25
+ name = name.to_s.upcase
26
+ args = default_value.eql?(NO_ARG) ? [name] : [name, default_value]
27
+
28
+ store.fetch(*args, &block)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,234 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/core/constants"
4
+ require "dry/configurable"
5
+ require_relative "errors"
6
+
7
+ module Hanami
8
+ # Provides user-defined settings for an Hanami app or slice.
9
+ #
10
+ # Define your own settings by inheriting from this class in `config/settings.rb` within an app or
11
+ # slice. Your settings will be loaded from matching ENV vars (with upper-cased names) and be
12
+ # registered as a component as part of the Hanami app {Hanami::Slice::ClassMethods#prepare
13
+ # prepare} step.
14
+ #
15
+ # The settings instance is registered in your app and slice containers as a `"settings"`
16
+ # component. You can use the `Deps` mixin to inject this dependency and make settings available to
17
+ # your other components as required.
18
+ #
19
+ # @example
20
+ # # config/settings.rb
21
+ # # frozen_string_literal: true
22
+ #
23
+ # module MyApp
24
+ # class Settings < Hanami::Settings
25
+ # Secret = Types::String.constrained(min_size: 20)
26
+ #
27
+ # setting :database_url, constructor: Types::String
28
+ # setting :session_secret, constructor: Secret
29
+ # setting :some_flag, default: false, constructor: Types::Params::Bool
30
+ # end
31
+ # end
32
+ #
33
+ # Settings are defined with [dry-configurable][dry-c]'s `setting` method. You may likely want to
34
+ # provide `default:` and `constructor:` options for your settings.
35
+ #
36
+ # If you have [dry-types][dry-t] bundled, then a nested `Types` module will be available for type
37
+ # checking your setting values. Pass type objects to the setting `constructor:` options to ensure
38
+ # their values meet your type expectations. You can use dry-types' default type objects or define
39
+ # your own.
40
+ #
41
+ # When the settings are initialized, all type errors will be collected and presented together for
42
+ # correction. Settings are loaded early, as part of the Hanami app's
43
+ # {Hanami::Slice::ClassMethods#prepare prepare} step, to ensure that the app boots only when valid
44
+ # settings are present.
45
+ #
46
+ # Setting values are loaded from a configurable store, which defaults to
47
+ # {Hanami::Settings::EnvStore}, which fetches the values from equivalent upper-cased keys in
48
+ # `ENV`. You can configure an alternative store via {Hanami::Config#settings_store}. Setting stores
49
+ # must implement a `#fetch` method with the same signature as `Hash#fetch`.
50
+ #
51
+ # [dry-c]: https://dry-rb.org/gems/dry-configurable/
52
+ # [dry-t]: https://dry-rb.org/gems/dry-types/
53
+ #
54
+ # @see Hanami::Settings::DotenvStore
55
+ #
56
+ # @api public
57
+ # @since 2.0.0
58
+ class Settings
59
+ # Error raised when setting values do not meet their type expectations.
60
+ #
61
+ # Its message collects all the individual errors that can be raised for each setting.
62
+ #
63
+ # @api public
64
+ # @since 2.0.0
65
+ class InvalidSettingsError < Hanami::Error
66
+ # @api private
67
+ def initialize(errors)
68
+ super()
69
+ @errors = errors
70
+ end
71
+
72
+ # Returns the exception's message.
73
+ #
74
+ # @return [String]
75
+ #
76
+ # @api public
77
+ # @since 2.0.0
78
+ def to_s
79
+ <<~STR.strip
80
+ Could not initialize settings. The following settings were invalid:
81
+
82
+ #{@errors.map { |setting, message| "#{setting}: #{message}" }.join("\n")}
83
+ STR
84
+ end
85
+ end
86
+
87
+ class << self
88
+ # Defines a nested `Types` constant in `Settings` subclasses if dry-types is bundled.
89
+ #
90
+ # @see https://dry-rb.org/gems/dry-types
91
+ #
92
+ # @api private
93
+ def inherited(subclass)
94
+ super
95
+
96
+ if Hanami.bundled?("dry-types")
97
+ require "dry/types"
98
+ subclass.const_set(:Types, Dry.Types())
99
+ end
100
+ end
101
+
102
+ # Loads the settings for a slice.
103
+ #
104
+ # Returns nil if no settings class is defined.
105
+ #
106
+ # @return [Settings, nil]
107
+ #
108
+ # @api private
109
+ def load_for_slice(slice)
110
+ return unless settings_defined?(slice)
111
+
112
+ require_slice_settings(slice) unless slice_settings_class?(slice)
113
+
114
+ slice_settings_class(slice).new(slice.config.settings_store)
115
+ end
116
+
117
+ private
118
+
119
+ # Returns true if settings are defined for the slice.
120
+ #
121
+ # Settings are considered defined if a `Settings` class is already defined in the slice
122
+ # namespace, or a `config/settings.rb` exists under the slice root.
123
+ def settings_defined?(slice)
124
+ slice.namespace.const_defined?(SETTINGS_CLASS_NAME) ||
125
+ slice.root.join("#{SETTINGS_PATH}#{RB_EXT}").file?
126
+ end
127
+
128
+ def slice_settings_class?(slice)
129
+ slice.namespace.const_defined?(SETTINGS_CLASS_NAME)
130
+ end
131
+
132
+ def slice_settings_class(slice)
133
+ slice.namespace.const_get(SETTINGS_CLASS_NAME)
134
+ end
135
+
136
+ def require_slice_settings(slice)
137
+ require "hanami/settings"
138
+
139
+ slice_settings_require_path = File.join(slice.root, SETTINGS_PATH)
140
+
141
+ begin
142
+ require slice_settings_require_path
143
+ rescue LoadError => exception
144
+ raise exception unless exception.path == slice_settings_require_path
145
+ end
146
+ end
147
+ end
148
+
149
+ # @api private
150
+ Undefined = Dry::Core::Constants::Undefined
151
+
152
+ # @api private
153
+ EMPTY_STORE = Dry::Core::Constants::EMPTY_HASH
154
+
155
+ include Dry::Configurable
156
+
157
+ # @api private
158
+ def initialize(store = EMPTY_STORE)
159
+ errors = config._settings.map(&:name).each_with_object({}) do |name, errs|
160
+ value = store.fetch(name, Undefined)
161
+
162
+ if value.eql?(Undefined)
163
+ # When a key is missing entirely from the store, _read_ its value from the config instead.
164
+ # This ensures its setting constructor runs (with a `nil` argument given) and raises any
165
+ # necessary errors.
166
+ public_send(name)
167
+ else
168
+ public_send("#{name}=", value)
169
+ end
170
+ rescue => exception # rubocop:disable Style/RescueStandardError
171
+ errs[name] = exception
172
+ end
173
+
174
+ raise InvalidSettingsError, errors if errors.any?
175
+
176
+ config.finalize!
177
+ end
178
+
179
+ # Returns a string containing a human-readable representation of the settings.
180
+ #
181
+ # This includes setting names only, not any values, to ensure that sensitive values do not
182
+ # inadvertently leak.
183
+ #
184
+ # Use {#inspect_values} to inspect settings with their values.
185
+ #
186
+ # @example
187
+ # settings.inspect
188
+ # # => #<MyApp::Settings [database_url, session_secret, some_flag]>
189
+ #
190
+ # @return [String]
191
+ #
192
+ # @see #inspect_values
193
+ #
194
+ # @api public
195
+ # @since 2.0.0
196
+ def inspect
197
+ "#<#{self.class} [#{config._settings.map(&:name).join(", ")}]>"
198
+ end
199
+
200
+ # rubocop:disable Layout/LineLength
201
+
202
+ # Returns a string containing a human-readable representation of the settings and their values.
203
+ #
204
+ # @example
205
+ # settings.inspect_values
206
+ # # => #<MyApp::Settings database_url="postgres://localhost/my_db", session_secret="xxx", some_flag=true]>
207
+ #
208
+ # @return [String]
209
+ #
210
+ # @see #inspect
211
+ #
212
+ # @api public
213
+ # @since 2.0.0
214
+ def inspect_values
215
+ "#<#{self.class} #{config._settings.map { |setting| "#{setting.name}=#{config[setting.name].inspect}" }.join(" ")}>"
216
+ end
217
+
218
+ # rubocop:enable Layout/LineLength
219
+
220
+ private
221
+
222
+ def method_missing(name, *args, &block)
223
+ if config.respond_to?(name)
224
+ config.send(name, *args, &block)
225
+ else
226
+ super
227
+ end
228
+ end
229
+
230
+ def respond_to_missing?(name, _include_all = false)
231
+ config.respond_to?(name) || super
232
+ end
233
+ end
234
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/setup"
4
+ require "hanami"
5
+
6
+ Hanami.setup