karafka-core 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 82bb5d4340cf638f60cb93f47188e0eb09c25a47a8c4a0d3cfbe556b2d861703
4
+ data.tar.gz: f2fec7fa22658d92539e3cfae8c73f4a00a903160e7b5ca73b5f5236873f2195
5
+ SHA512:
6
+ metadata.gz: 480bc8f93ca8efd92cad4c9bc77c28ef5e43947f9603b1b56060bd8ff769a1b7f0c83729d2ad8f22b2a37e57aa913b996ea919458f4c60491c9266d772eba5ea
7
+ data.tar.gz: 8c578ff0a9d8a0e7e81601ae5a1e6b318b79dc12b9aeba65046bebf384e16fdd9adfac03aec60adbd3d4f03a4ab396fd3aeeea4219c1b29bb91741c72cb26df8
checksums.yaml.gz.sig ADDED
Binary file
data/.coditsu/ci.yml ADDED
@@ -0,0 +1,3 @@
1
+ repository_id: 'd3cd0fec-757e-47be-87ca-7829dff0c5f4'
2
+ api_key: <%= ENV['CODITSU_API_KEY'] %>
3
+ api_secret: <%= ENV['CODITSU_API_SECRET'] %>
data/.console_irbrc ADDED
@@ -0,0 +1,11 @@
1
+ # irbrc for Karafka console
2
+
3
+ IRB.conf[:AUTO_INDENT] = true
4
+ IRB.conf[:SAVE_HISTORY] = 1000
5
+ IRB.conf[:USE_READLINE] = true
6
+ IRB.conf[:HISTORY_FILE] = ".irb-history"
7
+ IRB.conf[:LOAD_MODULES] = [] unless IRB.conf.key?(:LOAD_MODULES)
8
+
9
+ unless IRB.conf[:LOAD_MODULES].include?('irb/completion')
10
+ IRB.conf[:LOAD_MODULES] << 'irb/completion'
11
+ end
data/.diffend.yml ADDED
@@ -0,0 +1,3 @@
1
+ project_id: '199f1b30-ba87-49e1-96d8-f4ea86732443'
2
+ shareable_id: '6a6f2b22-021c-40cd-885c-82838f84f2f9'
3
+ shareable_key: '9c7e0a66-7bff-4b90-9528-69d8d4c0bba4'
@@ -0,0 +1,50 @@
1
+ ---
2
+ name: Bug Report
3
+ about: Report an issue with Karafka you've discovered.
4
+ ---
5
+
6
+ *Be clear, concise and precise in your description of the problem.
7
+ Open an issue with a descriptive title and a summary in grammatically correct,
8
+ complete sentences.*
9
+
10
+ *Use the template below when reporting bugs. Please, make sure that
11
+ you're running the latest stable Karafka and that the problem you're reporting
12
+ hasn't been reported (and potentially fixed) already.*
13
+
14
+ *Before filing the ticket you should replace all text above the horizontal
15
+ rule with your own words.*
16
+
17
+ --------
18
+
19
+ ## Expected behavior
20
+
21
+ Describe here how you expected Karafka to behave in this particular situation.
22
+
23
+ ## Actual behavior
24
+
25
+ Describe here what actually happened.
26
+
27
+ ## Steps to reproduce the problem
28
+
29
+ This is extremely important! Providing us with a reliable way to reproduce
30
+ a problem will expedite its solution.
31
+
32
+ ## Your setup details
33
+
34
+ Please provide kafka version and the output of `karafka info` or `bundle exec karafka info` if using Bundler.
35
+
36
+ Here's an example:
37
+
38
+ ```
39
+ $ [bundle exec] karafka info
40
+ Karafka version: 1.3.0
41
+ Ruby version: 2.6.3
42
+ Ruby-kafka version: 0.7.9
43
+ Application client id: karafka-local
44
+ Backend: inline
45
+ Batch fetching: true
46
+ Batch consuming: true
47
+ Boot file: /app/karafka/karafka.rb
48
+ Environment: development
49
+ Kafka seed brokers: ["kafka://kafka:9092"]
50
+ ```
@@ -0,0 +1,20 @@
1
+ ---
2
+ name: Feature Request
3
+ about: Suggest new Karafka features or improvements to existing features.
4
+ ---
5
+
6
+ ## Is your feature request related to a problem? Please describe.
7
+
8
+ A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
9
+
10
+ ## Describe the solution you'd like
11
+
12
+ A clear and concise description of what you want to happen.
13
+
14
+ ## Describe alternatives you've considered
15
+
16
+ A clear and concise description of any alternative solutions or features you've considered.
17
+
18
+ ## Additional context
19
+
20
+ Add any other context or screenshots about the feature request here.
@@ -0,0 +1,74 @@
1
+ name: ci
2
+
3
+ concurrency: ci-${{ github.ref }}
4
+
5
+ on:
6
+ pull_request:
7
+ push:
8
+ schedule:
9
+ - cron: '0 1 * * *'
10
+
11
+ jobs:
12
+ specs:
13
+ runs-on: ubuntu-latest
14
+ needs: diffend
15
+ strategy:
16
+ fail-fast: false
17
+ matrix:
18
+ ruby:
19
+ - '3.1'
20
+ - '3.0'
21
+ - '2.7'
22
+ include:
23
+ - ruby: '3.1'
24
+ coverage: 'true'
25
+ steps:
26
+ - uses: actions/checkout@v2
27
+ - name: Install package dependencies
28
+ run: "[ -e $APT_DEPS ] || sudo apt-get install -y --no-install-recommends $APT_DEPS"
29
+ - name: Set up Ruby
30
+ uses: ruby/setup-ruby@v1
31
+ with:
32
+ ruby-version: ${{matrix.ruby}}
33
+ - name: Install latest bundler
34
+ run: |
35
+ gem install bundler --no-document
36
+ bundle config set without 'tools benchmarks docs'
37
+ - name: Bundle install
38
+ run: |
39
+ bundle config set without development
40
+ bundle install --jobs 4 --retry 3
41
+ - name: Run all tests
42
+ env:
43
+ GITHUB_COVERAGE: ${{matrix.coverage}}
44
+ run: bundle exec rspec
45
+
46
+ diffend:
47
+ runs-on: ubuntu-latest
48
+ strategy:
49
+ fail-fast: false
50
+ steps:
51
+ - uses: actions/checkout@v2
52
+ with:
53
+ fetch-depth: 0
54
+ - name: Set up Ruby
55
+ uses: ruby/setup-ruby@v1
56
+ with:
57
+ ruby-version: 3.1
58
+ - name: Install latest bundler
59
+ run: gem install bundler --no-document
60
+ - name: Install Diffend plugin
61
+ run: bundle plugin install diffend
62
+ - name: Bundle Secure
63
+ run: bundle secure
64
+
65
+ coditsu:
66
+ runs-on: ubuntu-latest
67
+ strategy:
68
+ fail-fast: false
69
+ steps:
70
+ - uses: actions/checkout@v2
71
+ with:
72
+ fetch-depth: 0
73
+ - name: Run Coditsu
74
+ run: \curl -sSL https://api.coditsu.io/run/ci | bash
data/.gitignore ADDED
@@ -0,0 +1,69 @@
1
+ # bundler state
2
+ /.bundle
3
+ /vendor/bundle/
4
+ /vendor/ruby/
5
+ /ruby/
6
+ app.god
7
+
8
+ # minimal Rails specific artifacts
9
+ /.coditsu/local.yml
10
+ db/*.sqlite3
11
+ /log/development.log
12
+ /log/production.log
13
+ /log/test.log
14
+ /tmp/*
15
+ *.gem
16
+ *.~
17
+
18
+ # various artifacts
19
+ **.war
20
+ *.rbc
21
+ *.sassc
22
+ .byebug_history
23
+ .redcar/
24
+ .capistrano/
25
+ .sass-cache
26
+ /config/god/sidekiq.rb
27
+ /config/puma.rb
28
+ /coverage.data
29
+ /coverage/
30
+ /doc/api/
31
+ /doc/app/
32
+ /doc/yard
33
+ /doc/features.html
34
+ /doc/specs.html
35
+ /spec/tmp/*
36
+ /cache
37
+ /capybara*
38
+ /capybara-*.html
39
+ /gems
40
+ /specifications
41
+ rerun.txt
42
+ pickle-email-*.html
43
+
44
+ # If you find yourself ignoring temporary files generated by your text editor
45
+ # or operating system, you probably want to add a global ignore instead:
46
+ # git config --global core.excludesfile ~/.gitignore_global
47
+ #
48
+ # Here are some files you may want to ignore globally:
49
+
50
+ # scm revert files
51
+ **.orig
52
+
53
+ # Mac finder artifacts
54
+ .DS_Store
55
+
56
+ # Netbeans project directory
57
+ /nbproject
58
+
59
+ # RubyMine project files
60
+ .idea
61
+
62
+ # Textmate project files
63
+ /*.tmproj
64
+
65
+ # vim artifacts
66
+ **.swp
67
+
68
+ # documentation
69
+ .yardoc
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ karafka-core
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.1.2
data/CHANGELOG.md ADDED
@@ -0,0 +1,4 @@
1
+ # Karafka core changelog
2
+
3
+ ## 2.0.0.beta1
4
+ - Initial extraction of common components used in the Karafka ecosystem from WaterDrop.
@@ -0,0 +1,46 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
6
+
7
+ ## Our Standards
8
+
9
+ Examples of behavior that contributes to creating a positive environment include:
10
+
11
+ * Using welcoming and inclusive language
12
+ * Being respectful of differing viewpoints and experiences
13
+ * Gracefully accepting constructive criticism
14
+ * Focusing on what is best for the community
15
+ * Showing empathy towards other community members
16
+
17
+ Examples of unacceptable behavior by participants include:
18
+
19
+ * The use of sexualized language or imagery and unwelcome sexual attention or advances
20
+ * Trolling, insulting/derogatory comments, and personal or political attacks
21
+ * Public or private harassment
22
+ * Publishing others' private information, such as a physical or electronic address, without explicit permission
23
+ * Other conduct which could reasonably be considered inappropriate in a professional setting
24
+
25
+ ## Our Responsibilities
26
+
27
+ Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28
+
29
+ Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30
+
31
+ ## Scope
32
+
33
+ This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
34
+
35
+ ## Enforcement
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at maciej@mensfeld.pl. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
38
+
39
+ Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
40
+
41
+ ## Attribution
42
+
43
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
44
+
45
+ [homepage]: http://contributor-covenant.org
46
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ plugin 'diffend'
6
+
7
+ gemspec
8
+
9
+ group :test do
10
+ gem 'byebug'
11
+ gem 'factory_bot'
12
+ gem 'rspec'
13
+ gem 'simplecov'
14
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,57 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ karafka-core (2.0.0)
5
+ concurrent-ruby (>= 1.1)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activesupport (7.0.3.1)
11
+ concurrent-ruby (~> 1.0, >= 1.0.2)
12
+ i18n (>= 1.6, < 2)
13
+ minitest (>= 5.1)
14
+ tzinfo (~> 2.0)
15
+ byebug (11.1.3)
16
+ concurrent-ruby (1.1.10)
17
+ diff-lcs (1.5.0)
18
+ docile (1.4.0)
19
+ factory_bot (6.2.1)
20
+ activesupport (>= 5.0.0)
21
+ i18n (1.12.0)
22
+ concurrent-ruby (~> 1.0)
23
+ minitest (5.16.2)
24
+ rspec (3.11.0)
25
+ rspec-core (~> 3.11.0)
26
+ rspec-expectations (~> 3.11.0)
27
+ rspec-mocks (~> 3.11.0)
28
+ rspec-core (3.11.0)
29
+ rspec-support (~> 3.11.0)
30
+ rspec-expectations (3.11.0)
31
+ diff-lcs (>= 1.2.0, < 2.0)
32
+ rspec-support (~> 3.11.0)
33
+ rspec-mocks (3.11.1)
34
+ diff-lcs (>= 1.2.0, < 2.0)
35
+ rspec-support (~> 3.11.0)
36
+ rspec-support (3.11.0)
37
+ simplecov (0.21.2)
38
+ docile (~> 1.1)
39
+ simplecov-html (~> 0.11)
40
+ simplecov_json_formatter (~> 0.1)
41
+ simplecov-html (0.12.3)
42
+ simplecov_json_formatter (0.1.4)
43
+ tzinfo (2.0.5)
44
+ concurrent-ruby (~> 1.0)
45
+
46
+ PLATFORMS
47
+ x86_64-linux
48
+
49
+ DEPENDENCIES
50
+ byebug
51
+ factory_bot
52
+ karafka-core!
53
+ rspec
54
+ simplecov
55
+
56
+ BUNDLED WITH
57
+ 2.3.15
data/MIT-LICENSE ADDED
@@ -0,0 +1,18 @@
1
+ Permission is hereby granted, free of charge, to any person obtaining
2
+ a copy of this software and associated documentation files (the
3
+ "Software"), to deal in the Software without restriction, including
4
+ without limitation the rights to use, copy, modify, merge, publish,
5
+ distribute, sublicense, and/or sell copies of the Software, and to
6
+ permit persons to whom the Software is furnished to do so, subject to
7
+ the following conditions:
8
+
9
+ The above copyright notice and this permission notice shall be
10
+ included in all copies or substantial portions of the Software.
11
+
12
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,21 @@
1
+ [![Build Status](https://github.com/karafka/karafka-core/actions/workflows/ci.yml/badge.svg)](https://github.com/karafka/karafka-core/actions/workflows/ci.yml)
2
+ [![Gem Version](https://badge.fury.io/rb/karafka-core.svg)](http://badge.fury.io/rb/karafka-core)
3
+ [![Join the chat at https://slack.karafka.io](https://raw.githubusercontent.com/karafka/misc/master/slack.svg)](https://slack.karafka.io)
4
+
5
+ ## Karafka-Core
6
+
7
+ Karafka-Core contains toolset of small support modules used throughout the [Karafka](https://github.com/karafka/karafka/) ecosystem.
8
+
9
+ It includes
10
+
11
+ - `Karafka::Core::Monitoring` - default instrumentation and abstraction that allows to use either itself, `dry-monitor` or `ActiveSupport::Notifications`.
12
+ - `Karafka::Core::Configurable` - configuration engine inspired by `dry-config` with similar but simplified API.
13
+ - `Karafka::Core::Contractable` - contracts inspired by `dry-validation` but with simplified API.
14
+
15
+ ## Note on contributions
16
+
17
+ First, thank you for considering contributing to the Karafka ecosystem! It's people like you that make the open source community such a great community!
18
+
19
+ Each pull request must pass all the RSpec specs, integration tests and meet our quality requirements.
20
+
21
+ Fork it, update and wait for the Github Actions results.
@@ -0,0 +1,25 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIEODCCAqCgAwIBAgIBATANBgkqhkiG9w0BAQsFADAjMSEwHwYDVQQDDBhtYWNp
3
+ ZWovREM9bWVuc2ZlbGQvREM9cGwwHhcNMjEwODExMTQxNTEzWhcNMjIwODExMTQx
4
+ NTEzWjAjMSEwHwYDVQQDDBhtYWNpZWovREM9bWVuc2ZlbGQvREM9cGwwggGiMA0G
5
+ CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDV2jKH4Ti87GM6nyT6D+ESzTI0MZDj
6
+ ak2/TEwnxvijMJyCCPKT/qIkbW4/f0VHM4rhPr1nW73sb5SZBVFCLlJcOSKOBdUY
7
+ TMY+SIXN2EtUaZuhAOe8LxtxjHTgRHvHcqUQMBENXTISNzCo32LnUxweu66ia4Pd
8
+ 1mNRhzOqNv9YiBZvtBf7IMQ+sYdOCjboq2dlsWmJiwiDpY9lQBTnWORnT3mQxU5x
9
+ vPSwnLB854cHdCS8fQo4DjeJBRZHhEbcE5sqhEMB3RZA3EtFVEXOxlNxVTS3tncI
10
+ qyNXiWDaxcipaens4ObSY1C2HTV7OWb7OMqSCIybeYTSfkaSdqmcl4S6zxXkjH1J
11
+ tnjayAVzD+QVXGijsPLE2PFnJAh9iDET2cMsjabO1f6l1OQNyAtqpcyQcgfnyW0z
12
+ g7tGxTYD+6wJHffM9d9txOUw6djkF6bDxyqB8lo4Z3IObCx18AZjI9XPS9QG7w6q
13
+ LCWuMG2lkCcRgASqaVk9fEf9yMc2xxz5o3kCAwEAAaN3MHUwCQYDVR0TBAIwADAL
14
+ BgNVHQ8EBAMCBLAwHQYDVR0OBBYEFBqUFCKCOe5IuueUVqOB991jyCLLMB0GA1Ud
15
+ EQQWMBSBEm1hY2llakBtZW5zZmVsZC5wbDAdBgNVHRIEFjAUgRJtYWNpZWpAbWVu
16
+ c2ZlbGQucGwwDQYJKoZIhvcNAQELBQADggGBADD0/UuTTFgW+CGk2U0RDw2RBOca
17
+ W2LTF/G7AOzuzD0Tc4voc7WXyrgKwJREv8rgBimLnNlgmFJLmtUCh2U/MgxvcilH
18
+ yshYcbseNvjkrtYnLRlWZR4SSB6Zei5AlyGVQLPkvdsBpNegcG6w075YEwzX/38a
19
+ 8V9B/Yri2OGELBz8ykl7BsXUgNoUPA/4pHF6YRLz+VirOaUIQ4JfY7xGj6fSOWWz
20
+ /rQ/d77r6o1mfJYM/3BRVg73a3b7DmRnE5qjwmSaSQ7u802pJnLesmArch0xGCT/
21
+ fMmRli1Qb+6qOTl9mzD6UDMAyFR4t6MStLm0mIEqM0nBO5nUdUWbC7l9qXEf8XBE
22
+ 2DP28p3EqSuS+lKbAWKcqv7t0iRhhmaod+Yn9mcrLN1sa3q3KSQ9BCyxezCD4Mk2
23
+ R2P11bWoCtr70BsccVrN8jEhzwXngMyI2gVt750Y+dbTu1KgRqZKp/ECe7ZzPzXj
24
+ pIy9vHxTANKYVyI4qj8OrFdEM5BQNu8oQpL0iQ==
25
+ -----END CERTIFICATE-----
data/config/errors.yml ADDED
@@ -0,0 +1,10 @@
1
+ en:
2
+ validations:
3
+ test:
4
+ missing: needs to be present
5
+ id_format: needs to be a String
6
+ nested.id2_format: needs to be a String
7
+
8
+ config:
9
+ missing: needs to be present
10
+ id_format: needs to be a String
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+
6
+ require 'karafka/core/version'
7
+
8
+ Gem::Specification.new do |spec|
9
+ spec.name = 'karafka-core'
10
+ spec.version = ::Karafka::Core::VERSION
11
+ spec.platform = Gem::Platform::RUBY
12
+ spec.authors = ['Maciej Mensfeld']
13
+ spec.email = %w[maciej@mensfeld.pl]
14
+ spec.homepage = 'https://karafka.io'
15
+ spec.summary = 'Karafka ecosystem core modules'
16
+ spec.description = 'A toolset of small support modules used throughout the Karafka ecosystem'
17
+ spec.licenses = %w[MIT]
18
+ spec.add_dependency 'concurrent-ruby', '>= 1.1'
19
+
20
+ spec.required_ruby_version = '>= 2.6.0'
21
+
22
+ if $PROGRAM_NAME.end_with?('gem')
23
+ spec.signing_key = File.expand_path('~/.ssh/gem-private_key.pem')
24
+ end
25
+
26
+ spec.cert_chain = %w[certs/mensfeld.pem]
27
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(spec)/}) }
28
+ spec.require_paths = %w[lib]
29
+
30
+ spec.metadata = {
31
+ 'source_code_uri' => 'https://github.com/karafka/karafka-core',
32
+ 'rubygems_mfa_required' => 'true'
33
+ }
34
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ module Core
5
+ module Configurable
6
+ # Single end config value representation
7
+ Leaf = Struct.new(:name, :default, :constructor)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ module Core
5
+ module Configurable
6
+ # Single non-leaf node
7
+ # This is a core component for the configurable settings
8
+ #
9
+ # The idea here is simple: we collect settings (leafs) and children (nodes) information and
10
+ # we only compile/initialize the values prior to user running the `#configure` API. This API
11
+ # needs to run prior to using the result stuff even if there is nothing to configure
12
+ class Node
13
+ attr_reader :name, :nestings
14
+
15
+ # We need to be able to redefine children for deep copy
16
+ attr_accessor :children
17
+
18
+ # @param name [Symbol] node name
19
+ # @param nestings [Proc] block for nested settings
20
+ def initialize(name, nestings = ->(_) {})
21
+ @name = name
22
+ @children = []
23
+ @nestings = nestings
24
+ instance_eval(&nestings)
25
+ end
26
+
27
+ # Allows for a single leaf or nested node definition
28
+ #
29
+ # @param name [Symbol] setting or nested node name
30
+ # @param default [Object] default value
31
+ # @param constructor [#call, nil] callable or nil
32
+ # @param block [Proc] block for nested settings
33
+ def setting(name, default: nil, constructor: nil, &block)
34
+ @children << if block
35
+ Node.new(name, block)
36
+ else
37
+ Leaf.new(name, default, constructor)
38
+ end
39
+ end
40
+
41
+ # Allows for the configuration and setup of the settings
42
+ #
43
+ # Compile settings, allow for overrides via yielding
44
+ # @return [Node] returns self after configuration
45
+ def configure
46
+ compile
47
+ yield(self) if block_given?
48
+ self
49
+ end
50
+
51
+ # @return [Hash] frozen config hash representation
52
+ def to_h
53
+ config = {}
54
+
55
+ @children.each do |value|
56
+ config[value.name] = if value.is_a?(Leaf)
57
+ public_send(value.name)
58
+ else
59
+ value.to_h
60
+ end
61
+ end
62
+
63
+ config.freeze
64
+ end
65
+
66
+ # Deep copies all the children nodes to allow us for templates building on a class level
67
+ # and non-side-effect usage on an instance/inherited.
68
+ # @return [Node] duplicated node
69
+ def deep_dup
70
+ dupped = Node.new(name, nestings)
71
+
72
+ dupped.children += children.map do |value|
73
+ value.is_a?(Leaf) ? value.dup : value.deep_dup
74
+ end
75
+
76
+ dupped
77
+ end
78
+
79
+ # Converts the settings definitions into end children
80
+ # @note It runs once, after things are compiled, they will not be recompiled again
81
+ def compile
82
+ @children.each do |value|
83
+ # Do not redefine something that was already set during compilation
84
+ # This will allow us to reconfigure things and skip override with defaults
85
+ next if respond_to?(value.name)
86
+
87
+ singleton_class.attr_accessor value.name
88
+
89
+ initialized = if value.is_a?(Leaf)
90
+ value.constructor ? value.constructor.call(value.default) : value.default
91
+ else
92
+ value.compile
93
+ value
94
+ end
95
+
96
+ public_send("#{value.name}=", initialized)
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end