declarative_initialization 0.1.0 → 0.1.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: 2def6406dabc72b117248ec302ac3fbb6b69dc2a67721abd229a1f5787ae50ce
4
- data.tar.gz: 1bfa5430363018213e882a330e5ee83267b65a282a7cfb4f3439243a70e79887
3
+ metadata.gz: 3e75bb2a0843cd7164493d2acedd4c50671ad63a010b0a2ca0061ec85caa2238
4
+ data.tar.gz: fd8829609b1523653b8b33820e04d28714c75a08e19056b555dd35e43d8a2cbd
5
5
  SHA512:
6
- metadata.gz: 150ee62b3d7034af1b9d171bbfe6f472914439c1b9af558b78f34c4e4e66a6fdf28f870af998d00fc0d73f2ef699f76cfe3443a675cdff047668d66f15179e87
7
- data.tar.gz: 84dabfae84540cd6d7e0fe130e33edd1eb4126fc5a8e32d83fea676c2401c297ae70fe6de6b6c4210228ea86d7789b90be5c17311af5880e320a701b405aa3b9
6
+ metadata.gz: 0bf42818fb4f780f28fdaa2a9da06db4f1c7332ef9393cb93d676a875459b63efebc904c267a0cb7815593b17123003763b3c30de97a314fd928d45a72f4a067
7
+ data.tar.gz: 5b3dc48637e3b8b8bdf226e06185da514c0ebb6b35c7d3aaacc6364d9342ef0f694e0df47052640986333aa6ee1533b1449814efe80f56d203f2dc569947e7e1
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  ## [Unreleased]
2
2
 
3
- ## [0.1.0] - 2025-03-05
3
+ ## [0.1.1] - 2025-05-02
4
+ - Refactor internals
5
+ - [BUGFIX] Only trigger `attr_reader` creation on initial class load (vs on every call to `#new`)
6
+
4
7
 
8
+ ## [0.1.0] - 2025-03-05
5
9
  - Initial release
data/README.md CHANGED
@@ -55,7 +55,7 @@ We support that by passing an optional block to `initialize_with` -- for instanc
55
55
 
56
56
  * If a method with same name already exists, we log a warning and do not create the `attr_reader`. In that case you'll need to reference the instance variable directly.
57
57
 
58
- * Because of this, best practice when referencing variables in the post-initialize block is use `@foo` rather than relying on the `foo` attr_reader
58
+ * Because of this, best practice when referencing variables in the post-initialize block is to use `@foo` rather than relying on the `foo` attr_reader
59
59
 
60
60
  * Due to ruby syntax limitations, we do not support referencing other fields directly in the declaration:
61
61
 
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "logger"
4
+
5
+ module DeclarativeInitialization
6
+ module ClassMethods
7
+ # Defines an initializer expecting the specified keyword arguments.
8
+ # @param args [Array<Symbol>] Required keyword arguments
9
+ # @param kwargs [Hash<Symbol, Object>] Optional keyword arguments (required, but have default values)
10
+ # @param post_initialize_block [Proc] Block to execute after initialization (optional)
11
+ def initialize_with(*args, **kwargs, &post_initialize_block)
12
+ declared = args + kwargs.keys
13
+ _validate_arguments!(declared)
14
+
15
+ _set_up_attribute_readers(declared)
16
+ _set_up_block_reader
17
+ _define_initializer(declared, kwargs, post_initialize_block)
18
+ end
19
+
20
+ private
21
+
22
+ def _class_name
23
+ name || "Anonymous Class"
24
+ end
25
+
26
+ def _logger
27
+ @_logger ||= if defined?(Rails) && Rails.respond_to?(:logger)
28
+ Rails.logger
29
+ else
30
+ logger = Logger.new($stdout)
31
+ logger.level = Logger::WARN
32
+ logger
33
+ end
34
+ end
35
+
36
+ def _validate_arguments!(declared)
37
+ return if declared.all? { |arg| arg.is_a?(Symbol) }
38
+
39
+ raise ArgumentError, "[#{_class_name}] All arguments to #initialize_with must be symbols"
40
+ end
41
+
42
+ def _set_up_attribute_readers(declared)
43
+ declared.each do |key|
44
+ if method_defined?(key)
45
+ _logger.warn "[#{_class_name}] Method ##{key} already exists -- skipping attr_reader generation"
46
+ else
47
+ attr_reader key
48
+ end
49
+ end
50
+ end
51
+
52
+ def _set_up_block_reader
53
+ if method_defined?(:block)
54
+ _logger.warn "[#{_class_name}] Method #block already exists -- may NOT be able to reference a block " \
55
+ "passed to #new as #block (use @block instead)"
56
+ else
57
+ attr_reader :block
58
+ end
59
+ end
60
+
61
+ def _define_initializer(declared, defaults, post_initialize_block)
62
+ define_method(:initialize) do |*given_args, **given_kwargs, &given_block|
63
+ class_name = self.class.name || "Anonymous Class"
64
+ _validate_initialization_arguments!(class_name, given_args, given_kwargs, declared, defaults)
65
+
66
+ declared.each do |key|
67
+ instance_variable_set(:"@#{key}", given_kwargs.fetch(key, defaults[key]))
68
+ end
69
+
70
+ instance_variable_set(:@block, given_block) if given_block
71
+ instance_exec(&post_initialize_block) if post_initialize_block
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DeclarativeInitialization
4
+ module InstanceMethods
5
+ private
6
+
7
+ def _validate_initialization_arguments!(class_name, given_args, given_kwargs, declared, defaults)
8
+ raise ArgumentError, "[#{class_name}] Only keyword arguments are accepted" unless given_args.empty?
9
+
10
+ missing = declared - given_kwargs.keys - defaults.keys
11
+ extra = given_kwargs.keys - declared
12
+
13
+ raise ArgumentError, "[#{class_name}] Missing keyword argument(s): #{missing.join(", ")}" unless missing.empty?
14
+ raise ArgumentError, "[#{class_name}] Unknown keyword argument(s): #{extra.join(", ")}" unless extra.empty?
15
+ end
16
+ end
17
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DeclarativeInitialization
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.1"
5
5
  end
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "declarative_initialization/version"
4
- require "logger"
4
+ require_relative "declarative_initialization/class_methods"
5
+ require_relative "declarative_initialization/instance_methods"
5
6
 
6
7
  module DeclarativeInitialization
7
8
  def self.included(base)
@@ -10,52 +11,6 @@ module DeclarativeInitialization
10
11
  extend ClassMethods
11
12
  end
12
13
  end
13
-
14
- module ClassMethods
15
- def initialize_with(*args, **kwargs, &post_initialize_block)
16
- declared = args + kwargs.keys
17
- raise ArgumentError, "initialize_with expects to receive symbols" unless declared.all? { |arg| arg.is_a?(Symbol) }
18
-
19
- defaults = kwargs
20
-
21
- define_method(:initialize) do |*given_args, **given_kwargs, &block|
22
- class_name = self.class.name || "Anonymous Class"
23
- raise ArgumentError, "[#{class_name}] Only accepts keyword arguments" unless given_args.empty?
24
-
25
- missing = declared - given_kwargs.keys - defaults.keys
26
- extra = given_kwargs.keys - declared
27
-
28
- raise ArgumentError, "[#{class_name}] Missing keyword arguments: #{missing.join(", ")}" unless missing.empty?
29
- raise ArgumentError, "[#{class_name}] Unknown keyword arguments: #{extra.join(", ")}" unless extra.empty?
30
-
31
- declared.each do |key|
32
- instance_variable_set(:"@#{key}", given_kwargs.fetch(key, defaults[key]))
33
- if respond_to?(key, true)
34
- __logger.warn "Method ##{key} already exists on #{self.class.name}. Skipping attr_reader generation."
35
- else
36
- self.class.send(:attr_reader, key)
37
- end
38
- end
39
-
40
- if block # Automatically record any block passed to .new as an instance variable
41
- instance_variable_set(:@block, block)
42
- self.class.send(:attr_reader, :block) unless respond_to?(:block)
43
- end
44
-
45
- instance_exec(&post_initialize_block) if post_initialize_block
46
- end
47
- end
48
- end
49
-
50
- module InstanceMethods
51
- def __logger
52
- @__logger ||= begin
53
- Rails.logger
54
- rescue NameError
55
- Logger.new($stdout)
56
- end
57
- end
58
- end
59
14
  end
60
15
 
61
16
  # Set up an alias so you can also do `include InitializeWith`
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: declarative_initialization
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kali Donovan
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2025-03-07 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies: []
13
12
  description: A declarative replacement for `def initialize` in keyword-argument-based
14
13
  POROs.
@@ -26,6 +25,8 @@ files:
26
25
  - README.md
27
26
  - Rakefile
28
27
  - lib/declarative_initialization.rb
28
+ - lib/declarative_initialization/class_methods.rb
29
+ - lib/declarative_initialization/instance_methods.rb
29
30
  - lib/declarative_initialization/version.rb
30
31
  homepage: https://github.com/teamshares/declarative_initialization
31
32
  licenses: []
@@ -33,7 +34,6 @@ metadata:
33
34
  homepage_uri: https://github.com/teamshares/declarative_initialization
34
35
  source_code_uri: https://github.com/teamshares/declarative_initialization
35
36
  changelog_uri: https://github.com/teamshares/declarative_initialization/blob/main/CHANGELOG.md
36
- post_install_message:
37
37
  rdoc_options: []
38
38
  require_paths:
39
39
  - lib
@@ -48,8 +48,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
48
48
  - !ruby/object:Gem::Version
49
49
  version: '0'
50
50
  requirements: []
51
- rubygems_version: 3.4.10
52
- signing_key:
51
+ rubygems_version: 3.6.8
53
52
  specification_version: 4
54
53
  summary: Reduce initialization boilerplate for Ruby classes
55
54
  test_files: []