topping 0.0.1

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
+ SHA1:
3
+ metadata.gz: d56837f3a227355acadb988324896023b04bb271
4
+ data.tar.gz: 6d78c71af47e6453e3ee5e0edf58ff6b97f5da2b
5
+ SHA512:
6
+ metadata.gz: fcf70b23f49fdba1509b6eb5a988d942a8ba8ffbc00956ef40a195a641b01d70766f8a67f929e9a35034907b8e3fa904de6c2f8e14718bdd244ade49b87061ec
7
+ data.tar.gz: 10533fe300383d34b1c37040d01ebb486a8d65654da5dac4466fbf7d6f5cbec17babe5eacd28fbe18fa19a6c6e3bf69ab32f7a2cc8bdaf62e80974327c07e8ca
data/.gitignore ADDED
@@ -0,0 +1,30 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ ### https://raw.github.com/github/gitignore/0aeefb48c0ac885a516fb92f7f5bfd7e85ce7a37/Rails.gitignore
11
+ /verndor/bundle
12
+
13
+ *.rbc
14
+ *.sassc
15
+ .sass-cache
16
+ capybara-*.html
17
+ .rvmrc
18
+ /.bundle
19
+ /vendor/bundle/
20
+ /log/*
21
+ /tmp/*
22
+ /db/*.sqlite3
23
+ /public/system/*
24
+ /coverage/
25
+ /spec/tmp/*
26
+ **.orig
27
+ rerun.txt
28
+ pickle-email-*.html
29
+ .project
30
+
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.rubocop.yml ADDED
@@ -0,0 +1,45 @@
1
+
2
+ AllCops:
3
+ TargetRubyVersion: 2.3.4
4
+ Exclude:
5
+ - 'vendor/**/*'
6
+ - 'spec/fixtures/**/*'
7
+ - 'tmp/**/*'
8
+ ##################### Metrics ##################################
9
+
10
+ Metrics/LineLength:
11
+ Max: 130
12
+
13
+ Metrics/ClassLength:
14
+ CountComments: false
15
+ Max: 150
16
+
17
+ Metrics/LineLength:
18
+ Max: 150
19
+
20
+ ##################### Style ##################################
21
+
22
+ # Use nested module/class definitions instead of compact style.
23
+ # NG: module Gem::Search
24
+ Style/ClassAndModuleChildren:
25
+ Enabled: false
26
+
27
+ Style/AsciiComments:
28
+ Enabled: false
29
+
30
+ Style/Documentation:
31
+ Enabled: false
32
+
33
+ Style/DotPosition:
34
+ EnforcedStyle: trailing
35
+
36
+ Style/FrozenStringLiteralComment:
37
+ Enabled: false
38
+
39
+ Metrics/BlockLength:
40
+ Exclude:
41
+ - 'spec/**/*'
42
+
43
+ Metrics/MethodLength:
44
+ CountComments: false # count full line comments?
45
+ Max: 30
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.4.1
5
+ before_install: gem install bundler -v 1.15.1
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at rike422@gmail.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in topping.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,12 @@
1
+ group :red_green_refactor, halt_on_fail: true do
2
+ guard :rubocop, all_on_start: false, cli: ['--format', 'clang', '-D'] do
3
+ watch(/.+\.rb$/)
4
+ watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) }
5
+ end
6
+
7
+ guard :rspec, cmd: 'bundle exec rspec --color --format documentation' do
8
+ watch(%r{^spec/.+_spec\.rb$})
9
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
10
+ watch('spec/spec_helper.rb') { 'spec' }
11
+ end
12
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2013-2016 Jimmy Cuadra
4
+ Copyright (c) 2017 Akira Takahashi
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in
14
+ all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,118 @@
1
+ # Topping
2
+
3
+ Configuration library for like a [Lita](https://github.com/litaio/lita) style application
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'topping'
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ```ruby
16
+
17
+ require 'topping'
18
+
19
+ module MockApplication
20
+ class Application
21
+ include Topping::Configurable::HQ
22
+ end
23
+ end
24
+
25
+ module MockApplication
26
+ module Features
27
+ class Base
28
+ include Topping::Configurable::Branch
29
+ end
30
+
31
+ class Net < MockApplication::Features::Base
32
+ config :host, required: true, type: String
33
+ config :port, required: true, type: Integer
34
+ end
35
+
36
+ class User < MockApplication::Features::Base
37
+ config :username, required: true, type: String
38
+ config :password, required: true, type: String
39
+ end
40
+ end
41
+ end
42
+
43
+ MockApplication::Application.build
44
+
45
+ MockApplication::Application.configure do |c|
46
+ c.features.net.host = 'github.com'
47
+ c.features.net.port = 80
48
+
49
+ c.features.user.username = 'akira takahashi'
50
+ c.features.user.password = 'password'
51
+ end
52
+
53
+ net = MockApplication::Features::Net.new
54
+ user = MockApplication::Features::User.new
55
+
56
+ p net.config.host
57
+ # => 'github.com'
58
+ p net.config.port
59
+ # => 89
60
+
61
+ p user.config.username
62
+ # => 'akira takahashi'
63
+ p user.config.password
64
+ # => 'password'
65
+
66
+ ```
67
+
68
+ or
69
+
70
+ ```ruby
71
+ require 'topping'
72
+
73
+ module MockApplication
74
+ class Application
75
+ include Topping::Configurable::HQ
76
+ end
77
+ end
78
+
79
+ module MockApplication
80
+ module Features
81
+ class Base
82
+ include Topping::Configurable::Branch
83
+ end
84
+
85
+ class Net < MockApplication::Features::Base
86
+ config :host, required: true, type: String
87
+ config :port, required: true, type: Integer
88
+ end
89
+
90
+ class User < MockApplication::Features::Base
91
+ config :username, required: true, type: String
92
+ config :password, required: true, type: String
93
+ end
94
+ end
95
+ end
96
+
97
+ MockApplication::Application.build
98
+
99
+ MockApplication::Features::Net.configure do |c|
100
+ c.host = 'github.com'
101
+ c.port = 80
102
+ end
103
+
104
+ MockApplication::Features::User.configure do |c|
105
+ c.username = 'akira takahashi'
106
+ c.password = 'password'
107
+ end
108
+
109
+ p MockApplication::Application.config.features.net.host
110
+ # => 'github.com'
111
+ p MockApplication::Application.config.features.net.port
112
+ # => 80
113
+ p MockApplication::Application.config.features.user.username
114
+ # => 'akira takahashi'
115
+ p MockApplication::Application.config.features.user.password
116
+ # => 'password'
117
+
118
+ ```
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'topping'
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require 'irb'
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,69 @@
1
+ module Topping
2
+ # Mixin to add the ability for a plugin to define configuration.
3
+ # @since 0.0.1
4
+ module Configurable
5
+ module Branch
6
+ def self.included(klass)
7
+ klass.extend(ClassMethods)
8
+ end
9
+
10
+ # The Leaf class configuration object.
11
+ # @return [Configuration, Config] The Leaf class configuration object.
12
+ # @since 0.0.1
13
+ def config
14
+ self.class.configuration_builder.configuration
15
+ end
16
+
17
+ module ClassMethods
18
+ # Initializes the configuration builder for any inheriting classes.
19
+ def inherited(klass)
20
+ super
21
+ klass.extend(Topping::Configurable::Branch::ChildClassMethods)
22
+ klass.configuration_builder = ConfigurationBuilder.new
23
+ Topping::Configurable::HQ.mapping(klass)
24
+ end
25
+ end
26
+
27
+ module ChildClassMethods
28
+ # A block to be executed after configuration is finalized.
29
+ # @return [#call, nil] The block.
30
+ # @since 0.0.1
31
+ # @api private
32
+ attr_accessor :after_config_block
33
+
34
+ # The plugins's {ConfigurationBuilder} object.
35
+ # @return [ConfigurationBuilder] The configuration builder.
36
+ # @since 0.0.1
37
+ # @api public
38
+ attr_accessor :configuration_builder
39
+ # Registers a block to be executed after configuration is finalized.
40
+ # @yieldparam config [Configuration] The handler's configuration object.
41
+ # @return [void]
42
+ # @since 0.0.1
43
+ def after_config(&block)
44
+ self.after_config_block = block
45
+ end
46
+
47
+ # Sets a configuration attribute on the plugin.
48
+ # @return [void]
49
+ # @since 0.0.1
50
+ # @see ConfigurationBuilder#config
51
+ def config(*args, **kwargs, &block)
52
+ if block
53
+ configuration_builder.config(*args, **kwargs, &block)
54
+ else
55
+ configuration_builder.config(*args, **kwargs)
56
+ end
57
+ end
58
+
59
+ # Yields the configuration object
60
+ # @yieldparam [Configuration] config The configuration object.
61
+ # @since 0.0.1
62
+ # @see ConfigurationBuilder#config
63
+ def configure(&block)
64
+ configuration_builder.configure(&block)
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,85 @@
1
+ module Topping
2
+ # Mixin to add the ability for a plugin to define configuration.
3
+ # @since 0.0.1
4
+ module Configurable
5
+ module HQ
6
+ # The top-level {ConfigurationBuilder} attribute.
7
+ # @return [Configuration] The root attribute.
8
+ attr_accessor :root
9
+
10
+ # The top-level {ConfigurationBuilder} attribute.
11
+ # @api private
12
+ attr_accessor :name_space
13
+
14
+ # Yields the configuration object
15
+ # @yieldparam [Configuration] config The configuration object.
16
+ # @since 0.0.1
17
+ # @see ConfigurationBuilder#config
18
+ def configure
19
+ yield root.configuration.send(name_space.first.to_sym)
20
+ end
21
+
22
+ # User configuration store
23
+ # @return [Configuration] The root attribute.
24
+ # @since 0.0.1
25
+ def config
26
+ root.configuration.send(name_space.first.to_sym)
27
+ end
28
+
29
+ def build
30
+ @root.build
31
+ end
32
+
33
+ # @api private
34
+ def mapping(klass)
35
+ keys = Topping::Configurable::HQ.undersocre_namespace(klass)
36
+ keys.delete(name_space)
37
+ klass_name = keys.pop
38
+
39
+ parent = keys.reduce(root) do |memo, key|
40
+ config = memo.children.find { |child| child.name == key }
41
+ config = memo.config(key) if config.nil?
42
+ config
43
+ end
44
+ parent.combine(klass_name, klass.configuration_builder)
45
+ end
46
+
47
+ class << self
48
+ # The top-level Configurable Class
49
+ # @api private
50
+ # @return [Configuration] The root attribute.
51
+ attr_accessor :hq_class
52
+
53
+ def included(klass)
54
+ klass.extend(Topping::Configurable::HQ)
55
+ end
56
+
57
+ def mapping(klass)
58
+ hq_class.mapping(klass)
59
+ end
60
+
61
+ def extended(klass)
62
+ super
63
+ self.hq_class = klass
64
+ root_config = ConfigurationBuilder.new
65
+ klass.root = root_config
66
+ klass.name_space = Topping::Configurable::HQ.undersocre_namespace(klass)
67
+ end
68
+
69
+ def undersocre_namespace(klass)
70
+ klass.name.split('::').map do |key|
71
+ Topping::Configurable::HQ.underscore(key)
72
+ end
73
+ end
74
+
75
+ def underscore(str)
76
+ str.gsub(/::/, '/').
77
+ gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').
78
+ gsub(/([a-z\d])([A-Z])/, '\1_\2').
79
+ tr('-', '_').
80
+ downcase
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,47 @@
1
+ require_relative 'configurable/hq'
2
+ require_relative 'configurable/branch'
3
+ require_relative 'configuration_builder'
4
+
5
+ module Topping
6
+ # Mixin to add the ability for a plugin to define configuration.
7
+ # @since 0.0.1
8
+ module Configurable
9
+ # A block to be executed after configuration is finalized.
10
+ # @return [#call, nil] The block.
11
+ # @since 0.0.1
12
+ # @api private
13
+ attr_accessor :after_config_block
14
+
15
+ # The plugins's {ConfigurationBuilder} object.
16
+ # @return [ConfigurationBuilder] The configuration builder.
17
+ # @since 0.0.1
18
+ # @api public
19
+ attr_accessor :configuration_builder
20
+
21
+ # Registers a block to be executed after configuration is finalized.
22
+ # @yieldparam config [Configuration] The handler's configuration object.
23
+ # @return [void]
24
+ # @since 0.0.1
25
+ def after_config(&block)
26
+ self.after_config_block = block
27
+ end
28
+
29
+ # Sets a configuration attribute on the plugin.
30
+ # @return [void]
31
+ # @since 0.0.1
32
+ # @see ConfigurationBuilder#config
33
+ def config(*args, **kwargs, &block)
34
+ if block
35
+ configuration_builder.config(*args, **kwargs, &block)
36
+ else
37
+ configuration_builder.config(*args, **kwargs)
38
+ end
39
+ end
40
+
41
+ # Initializes the configuration builder for any inheriting classes.
42
+ def inherited(klass)
43
+ super
44
+ klass.configuration_builder = ConfigurationBuilder.new
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,208 @@
1
+ module Topping
2
+ # An object that stores user settings
3
+ # @since 0.0.1
4
+ class Configuration
5
+ end
6
+
7
+ # Provides a DSL for building {Configuration} objects.
8
+ # @since 0.0.1
9
+ class ConfigurationBuilder
10
+ # An array of any nested configuration builders.
11
+ # @return [Array<ConfigurationBuilder>] The array of child configuration builders.
12
+ # @api private
13
+ attr_reader :children
14
+
15
+ # A object that stores user settings
16
+ # @return [Boolean] Whether or not the attribute is required.
17
+ # @api private
18
+ attr_reader :configuration
19
+
20
+ # An array of valid types for the attribute.
21
+ # @return [Array<Object>] The array of valid types.
22
+ # @api private
23
+ attr_reader :types
24
+
25
+ # A block used to validate the attribute.
26
+ # @return [Proc] The validation block.
27
+ # @api private
28
+ attr_reader :validator
29
+
30
+ # The name of the configuration attribute.
31
+ # @return [String, Symbol] The attribute's name.
32
+ # @api private
33
+ attr_accessor :name
34
+
35
+ # The value of the configuration attribute.
36
+ # @return [Object] The attribute's value.
37
+ # @api private
38
+ attr_accessor :value
39
+
40
+ # A boolean indicating whether or not the attribute must be set.
41
+ # @return [Boolean] Whether or not the attribute is required.
42
+ # @api private
43
+ attr_accessor :required
44
+
45
+ alias required? required
46
+
47
+ class << self
48
+ # Deeply freezes a configuration object so that it can no longer be modified.
49
+ # @param config [Configuration] The configuration object to freeze.
50
+ # @return [void]
51
+ # @api private
52
+ def freeze_config(config)
53
+ IceNine.deep_freeze!(config)
54
+ end
55
+ end
56
+
57
+ def initialize
58
+ @children = []
59
+ @name = :root
60
+ end
61
+
62
+ # Builds a {Configuration} object from the attributes defined on the builder.
63
+ # @param object [Configuration] The empty configuration object that will be extended to
64
+ # create the final form.
65
+ # @return [Configuration] The fully built configuration object.
66
+ # @api private
67
+ def build(object = Configuration.new)
68
+ container = if children.empty?
69
+ build_leaf(object)
70
+ else
71
+ build_nested(object)
72
+ end
73
+
74
+ @configuration = container.public_send(name)
75
+ end
76
+
77
+ # Returns a boolean indicating whether or not the attribute has any child attributes.
78
+ # @return [Boolean] Whether or not the attribute has any child attributes.
79
+ # @api private
80
+ def children?
81
+ !children.empty?
82
+ end
83
+
84
+ # Merges two configuration builders by making one an attribute on the other.
85
+ # @param name [String, Symbol] The name of the new attribute.
86
+ # @param attribute [ConfigurationBuilder] The configuration builder that should be its
87
+ # value.
88
+ # @return [void]
89
+ # @api private
90
+ def combine(name, attribute)
91
+ attribute.name = name
92
+
93
+ children << attribute
94
+ end
95
+
96
+ def configure
97
+ yield configuration
98
+ end
99
+
100
+ # rubocop:disable Metrics1/ParameterLists
101
+ # Declares a configuration attribute.
102
+ # @param name [String, Symbol] The attribute's name.
103
+ # @param types [Object, Array<Object>] Optional: One or more types that the attribute's value
104
+ # must be.
105
+ # @param type [Object, Array<Object>] Optional: One or more types that the attribute's value
106
+ # must be.
107
+ # @param required [Boolean] Whether or not this attribute must be set. If required
108
+ # @param default [Object] An optional default value for the attribute.
109
+ # @yield A block to be evaluated in the context of the new attribute. Used for
110
+ # defining nested configuration attributes and validators.
111
+ # @return [void]
112
+ def config(name, types: nil, type: nil, required: false, default: nil, &block)
113
+ attribute = self.class.new
114
+ attribute.name = name
115
+ attribute.types = types || type
116
+ attribute.required = required
117
+ attribute.value = default
118
+ attribute.instance_exec(&block) if block
119
+
120
+ children << attribute
121
+ attribute
122
+ end
123
+
124
+ # Sets the valid types for the configuration attribute.
125
+ # @param types [Object, Array<Object>] One or more valid types.
126
+ # @return [void]
127
+ # @api private
128
+ def types=(types)
129
+ @types = Array(types) if types
130
+ end
131
+
132
+ # Declares a block to be used to validate the value of an attribute whenever it's set.
133
+ # Validation blocks should return any object to indicate an error, or +nil+/+false+ if
134
+ # validation passed.
135
+ # @yield The code that performs validation.
136
+ # @return [void]
137
+ def validate!(&block)
138
+ validator = block
139
+
140
+ unless value.nil?
141
+ error = validator.call(value)
142
+ raise ValidationError, error if error
143
+ end
144
+
145
+ @validator = block
146
+ end
147
+
148
+ # Sets the value of the attribute, raising an error if it is not among the valid types.
149
+ # @param value [Object] The new value of the attribute.
150
+ # @return [void]
151
+ # @raise [TypeError] If the new value is not among the declared valid types.
152
+ # @api private
153
+ def value=(value)
154
+ ensure_valid_default_value(value)
155
+
156
+ @value = value
157
+ end
158
+
159
+ private
160
+
161
+ # Finalize a nested object.
162
+ def build_leaf(object)
163
+ this = self
164
+ run_validator = method(:run_validator)
165
+ types_validation = method(:types_validation!)
166
+
167
+ object.instance_exec do
168
+ define_singleton_method(this.name) { this.value }
169
+ define_singleton_method("#{this.name}=") do |value|
170
+ run_validator.call(value)
171
+ types_validation.call(value)
172
+ this.value = value
173
+ end
174
+ end
175
+ object
176
+ end
177
+
178
+ # Finalize the root builder or any builder with children.
179
+ def build_nested(object)
180
+ this = self
181
+
182
+ nested_object = Configuration.new
183
+ children.each { |child| child.build(nested_object) }
184
+ object.instance_exec { define_singleton_method(this.name) { nested_object } }
185
+
186
+ object
187
+ end
188
+
189
+ # rubocop:disable Style/CaseEquality:
190
+ # Check's the value's type from inside the finalized object.
191
+ def types_validation!(value)
192
+ raise ValidationError if types && types.none? { |type| type === value }
193
+ end
194
+
195
+ # Raise if value is non-nil and isn't one of the specified types.
196
+ def ensure_valid_default_value(value)
197
+ return unless !value.nil? && types && types.none? { |type| type === value }
198
+ raise TypeError
199
+ end
200
+
201
+ # Runs the validator from inside the build configuration object.
202
+ def run_validator(value)
203
+ return unless validator
204
+ error = validator.call(value)
205
+ raise ValidationError unless error.nil?
206
+ end
207
+ end
208
+ end
@@ -0,0 +1,4 @@
1
+ module Topping
2
+ class ValidationError < StandardError
3
+ end
4
+ end
@@ -0,0 +1,3 @@
1
+ module Topping
2
+ VERSION = '0.0.1'.freeze
3
+ end
data/lib/topping.rb ADDED
@@ -0,0 +1,9 @@
1
+ require 'topping/version'
2
+
3
+ module Topping
4
+ # Your code goes here...
5
+ end
6
+
7
+ require 'topping/configurable'
8
+ require 'topping/configuration_builder'
9
+ require 'topping/errors'
data/topping.gemspec ADDED
@@ -0,0 +1,34 @@
1
+ # coding: utf-8
2
+
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'topping/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'topping'
9
+ spec.version = Topping::VERSION
10
+ spec.authors = ['Akira Takahashi']
11
+ spec.email = ['rike422@gmail.com']
12
+
13
+ spec.summary = 'Ruby application customize library'
14
+ spec.description = 'Ruby application customize library'
15
+ spec.homepage = 'https://github.com/rike422/topping'
16
+ spec.license = 'MIT'
17
+
18
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
19
+ f.match(%r{^(test|spec|features)/})
20
+ end
21
+ spec.bindir = 'exe'
22
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
+ spec.require_paths = ['lib']
24
+
25
+ spec.add_development_dependency 'bundler'
26
+ spec.add_development_dependency 'rake'
27
+ spec.add_development_dependency 'rspec', '~> 3.0'
28
+ spec.add_development_dependency 'simplecov'
29
+ spec.add_development_dependency 'coveralls'
30
+ spec.add_development_dependency 'guard'
31
+ spec.add_development_dependency 'guard-rspec'
32
+ spec.add_development_dependency 'guard-rubocop', '~> 1.2.0'
33
+ spec.add_development_dependency 'pry'
34
+ end
metadata ADDED
@@ -0,0 +1,190 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: topping
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Akira Takahashi
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-07-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: simplecov
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: coveralls
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: guard
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: guard-rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: guard-rubocop
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 1.2.0
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 1.2.0
125
+ - !ruby/object:Gem::Dependency
126
+ name: pry
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ description: Ruby application customize library
140
+ email:
141
+ - rike422@gmail.com
142
+ executables: []
143
+ extensions: []
144
+ extra_rdoc_files: []
145
+ files:
146
+ - ".gitignore"
147
+ - ".rspec"
148
+ - ".rubocop.yml"
149
+ - ".travis.yml"
150
+ - CODE_OF_CONDUCT.md
151
+ - Gemfile
152
+ - Guardfile
153
+ - LICENSE.txt
154
+ - README.md
155
+ - Rakefile
156
+ - bin/console
157
+ - bin/setup
158
+ - lib/topping.rb
159
+ - lib/topping/configurable.rb
160
+ - lib/topping/configurable/branch.rb
161
+ - lib/topping/configurable/hq.rb
162
+ - lib/topping/configuration_builder.rb
163
+ - lib/topping/errors.rb
164
+ - lib/topping/version.rb
165
+ - topping.gemspec
166
+ homepage: https://github.com/rike422/topping
167
+ licenses:
168
+ - MIT
169
+ metadata: {}
170
+ post_install_message:
171
+ rdoc_options: []
172
+ require_paths:
173
+ - lib
174
+ required_ruby_version: !ruby/object:Gem::Requirement
175
+ requirements:
176
+ - - ">="
177
+ - !ruby/object:Gem::Version
178
+ version: '0'
179
+ required_rubygems_version: !ruby/object:Gem::Requirement
180
+ requirements:
181
+ - - ">="
182
+ - !ruby/object:Gem::Version
183
+ version: '0'
184
+ requirements: []
185
+ rubyforge_project:
186
+ rubygems_version: 2.5.1
187
+ signing_key:
188
+ specification_version: 4
189
+ summary: Ruby application customize library
190
+ test_files: []