fig_tree 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.
data/fig_tree.gemspec ADDED
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'fig_tree/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'fig_tree'
9
+ spec.version = FigTree::VERSION
10
+ spec.authors = ['Daniel Orner']
11
+ spec.email = ['daniel.orner@flipp.com']
12
+ spec.summary = 'Configuration framework for Ruby.'
13
+ spec.homepage = ''
14
+ spec.license = 'Apache-2.0'
15
+ spec.required_ruby_version = '2.3'
16
+
17
+ spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ['lib']
21
+
22
+ spec.add_dependency('activesupport', '>= 3.0.0')
23
+
24
+ spec.add_development_dependency('guard', '~> 2')
25
+ spec.add_development_dependency('guard-rspec', '~> 4')
26
+ spec.add_development_dependency('guard-rubocop', '~> 1')
27
+ spec.add_development_dependency('rspec', '~> 3')
28
+ spec.add_development_dependency('rspec_junit_formatter', '~>0.3')
29
+ spec.add_development_dependency('rubocop', '~> 0.72')
30
+ spec.add_development_dependency('rubocop-rspec', '~> 1.27')
31
+ end
data/lib/fig_tree.rb ADDED
@@ -0,0 +1,251 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fig_tree/version'
4
+
5
+ # frozen_string_literal: true
6
+
7
+ require 'active_support/concern'
8
+ require 'active_support/callbacks'
9
+
10
+ # Configuration module.
11
+ module FigTree
12
+ extend ActiveSupport::Concern
13
+
14
+ ConfigValue = Struct.new(:value, :default_value, :default_proc, :deprecation) do
15
+
16
+ # Reset value back to default.
17
+ def reset!
18
+ if self.value.is_a?(ConfigStruct)
19
+ self.value.reset!
20
+ else
21
+ self.value = self.default_value
22
+ end
23
+ end
24
+
25
+ # :nodoc:
26
+ def clone_and_reset
27
+ setting = ConfigValue.new(self.value, self.default_value,
28
+ self.default_proc, self.deprecation)
29
+ setting.reset!
30
+ setting
31
+ end
32
+
33
+ end
34
+
35
+ # Class that defines and keeps the configuration values.
36
+ class ConfigStruct
37
+ include ActiveSupport::Callbacks
38
+
39
+ define_callbacks :configure
40
+
41
+ # @param name [String]
42
+ def initialize(name)
43
+ @name = name
44
+ @settings = {}
45
+ @setting_objects = {}
46
+ @setting_templates = {}
47
+ end
48
+
49
+ # Reset config back to default values.
50
+ def reset!
51
+ @setting_objects = @setting_templates.map { |k, _| [k, []] }.to_h
52
+ @settings.values.each(&:reset!)
53
+ end
54
+
55
+ # Mark a configuration as deprecated and replaced with the new config.
56
+ # @param old_config [String]
57
+ # @param new_config [String]
58
+ def deprecate(old_config, new_config)
59
+ @settings[old_config.to_sym] ||= ConfigValue.new
60
+ @settings[old_config.to_sym].deprecation = new_config
61
+ end
62
+
63
+ # :nodoc:
64
+ def inspect
65
+ "#{@name}: #{@settings.inspect} #{@setting_objects.inspect}"
66
+ end
67
+
68
+ # @return [Hash]
69
+ def to_h
70
+ @settings.map { |k, v| [k, v.value] }.to_h
71
+ end
72
+
73
+ # :nodoc:
74
+ def clone_and_reset
75
+ new_config = self.clone
76
+ new_config.setting_objects = new_config.setting_objects.clone
77
+ new_config.settings = new_config.settings.map { |k, v| [k, v.clone_and_reset] }.to_h
78
+ new_config
79
+ end
80
+
81
+ # Define a setting template for an array of objects via a block:
82
+ # setting_object :producer do
83
+ # setting :topic
84
+ # setting :class_name
85
+ # end
86
+ # This will create the `producer` method to define these values as well
87
+ # as the `producer_objects` method to retrieve them.
88
+ # @param name [Symbol]
89
+ def setting_object(name, &block)
90
+ new_config = ConfigStruct.new("#{@name}.#{name}")
91
+ @setting_objects[name] = []
92
+ @setting_templates[name] = new_config
93
+ new_config.instance_eval(&block)
94
+ end
95
+
96
+ # Define a setting with the given name.
97
+ # @param name [Symbol]
98
+ # @param default_value [Object]
99
+ # @param default_proc [Proc]
100
+ def setting(name, default_value=nil, default_proc: nil, &block)
101
+ if block_given?
102
+ # Create a nested setting
103
+ setting_config = @settings[name]&.value || ConfigStruct.new("#{@name}.#{name}")
104
+ setting = ConfigValue.new
105
+ setting.value = setting_config
106
+ @settings[name] = setting
107
+ setting_config.instance_eval(&block)
108
+ else
109
+ setting = ConfigValue.new
110
+ setting.default_proc = default_proc
111
+ setting.default_value = default_value
112
+ setting.reset!
113
+ @settings[name] = setting
114
+ end
115
+ end
116
+
117
+ # :nodoc:
118
+ def respond_to_missing?(method, include_all=true)
119
+ method = method.to_s.sub(/=$/, '')
120
+ method.ends_with?('objects') ||
121
+ @setting_templates.key?(method.to_sym) ||
122
+ @settings.key?(method.to_sym) ||
123
+ super
124
+ end
125
+
126
+ # :nodoc:
127
+ def method_missing(method, *args, &block)
128
+ config_key = method.to_s.sub(/=$/, '').to_sym
129
+
130
+ # Return the list of setting objects with the given name
131
+ if config_key.to_s.end_with?('objects')
132
+ return _setting_object_method(config_key)
133
+ end
134
+
135
+ # Define a new setting object with the given name
136
+ if @setting_templates.key?(config_key) && block_given?
137
+ return _new_setting_object_method(config_key, &block)
138
+ end
139
+
140
+ setting = @settings[config_key]
141
+
142
+ if setting&.deprecation
143
+ return _deprecated_config_method(method, *args)
144
+ end
145
+
146
+ return super unless setting
147
+
148
+ if block_given?
149
+ return _block_config_method(config_key, &block)
150
+ end
151
+
152
+ _default_config_method(config_key, *args)
153
+ end
154
+
155
+ protected
156
+
157
+ # Only for the clone method
158
+ attr_accessor :settings, :setting_objects
159
+
160
+ private
161
+
162
+ def _deprecated_config_method(method, *args)
163
+ config_key = method.to_s.sub(/=$/, '').to_sym
164
+ new_config = @settings[config_key].deprecation
165
+ equals = method.to_s.end_with?('=') ? '=' : ''
166
+ warning = "config.#{config_key}#{equals} is deprecated - use config.#{new_config}#{equals}"
167
+ ActiveSupport::Deprecation.warn(warning)
168
+ obj = self
169
+ messages = new_config.split('.')
170
+ messages[0..-2].each do |message|
171
+ obj = obj.send(message)
172
+ end
173
+ if args.length.positive?
174
+ obj.send(messages[-1], args[0])
175
+ else
176
+ obj.send(messages[-1])
177
+ end
178
+ end
179
+
180
+ # Get or set a value.
181
+ def _default_config_method(config_key, *args)
182
+ if args.length.positive?
183
+ # Set the value
184
+ @settings[config_key].value = args[0]
185
+ else
186
+ # Get the value
187
+ setting = @settings[config_key]
188
+ if setting.default_proc && setting.value.nil?
189
+ setting.value = setting.default_proc.call
190
+ end
191
+ setting.value
192
+ end
193
+ end
194
+
195
+ # Define a new setting object and use the passed block to define values.
196
+ def _new_setting_object_method(config_key, &block)
197
+ new_config = @setting_templates[config_key].clone_and_reset
198
+ new_config.instance_eval(&block)
199
+ @setting_objects[config_key] << new_config
200
+ end
201
+
202
+ # Return a setting object.
203
+ def _setting_object_method(config_key)
204
+ key = config_key.to_s.sub(/_objects$/, '').to_sym
205
+ @setting_objects[key]
206
+ end
207
+
208
+ # Define new values inside a block.
209
+ def _block_config_method(config_key, &block)
210
+ unless @settings[config_key].value.is_a?(ConfigStruct)
211
+ raise "Block called for #{config_key} but it is not a nested config!"
212
+ end
213
+
214
+ @settings[config_key].value.instance_eval(&block)
215
+ end
216
+ end
217
+
218
+ # :nodoc:
219
+ module ClassMethods
220
+ # Define and redefine settings.
221
+ def define_settings(&block)
222
+ config.instance_eval(&block)
223
+ end
224
+
225
+ # Configure the settings with values.
226
+ def configure(&block)
227
+ if defined?(Rake) && defined?(Rake.application)
228
+ tasks = Rake.application.top_level_tasks
229
+ if tasks.any? { |t| %w(assets webpacker yarn).include?(t.split(':').first) }
230
+ puts 'Skipping Deimos configuration since we are in JS/CSS compilation'
231
+ return
232
+ end
233
+ end
234
+ config.run_callbacks(:configure) do
235
+ config.instance_eval(&block)
236
+ end
237
+ end
238
+
239
+ # @return [ConfigStruct]
240
+ def config
241
+ @config ||= ConfigStruct.new('config')
242
+ end
243
+
244
+ # Pass a block to run after configuration is done.
245
+ def after_configure(&block)
246
+ mod = self
247
+ config.class.set_callback(:configure, :after,
248
+ proc { mod.instance_eval(&block) })
249
+ end
250
+ end
251
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FigTree
4
+ VERSION = '0.0.1'
5
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ $LOAD_PATH.unshift(File.expand_path('../lib', __dir__))
4
+
5
+ RSpec.configure do |config|
6
+ config.full_backtrace = true
7
+
8
+ # true by default for RSpec 4.0
9
+ config.shared_context_metadata_behavior = :apply_to_host_groups
10
+
11
+ config.mock_with(:rspec) do |mocks|
12
+ mocks.yield_receiver_to_any_instance_implementation_blocks = true
13
+ mocks.verify_partial_doubles = true
14
+ end
15
+ end
Binary file
metadata ADDED
@@ -0,0 +1,173 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fig_tree
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Daniel Orner
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-03-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 3.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 3.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: guard
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: guard-rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '4'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '4'
55
+ - !ruby/object:Gem::Dependency
56
+ name: guard-rubocop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec_junit_formatter
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.3'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.3'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.72'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.72'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop-rspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '1.27'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '1.27'
125
+ description:
126
+ email:
127
+ - daniel.orner@flipp.com
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - ".circleci/config.yml"
133
+ - ".gitignore"
134
+ - ".rspec"
135
+ - ".rubocop.yml"
136
+ - ".ruby-gemset"
137
+ - ".ruby-version"
138
+ - CHANGELOG.md
139
+ - CODE_OF_CONDUCT.md
140
+ - Gemfile
141
+ - Guardfile
142
+ - LICENSE.md
143
+ - README.md
144
+ - fig_tree.gemspec
145
+ - lib/fig_tree.rb
146
+ - lib/fig_tree/version.rb
147
+ - spec/spec_helper.rb
148
+ - support/flipp-logo.png
149
+ homepage: ''
150
+ licenses:
151
+ - Apache-2.0
152
+ metadata: {}
153
+ post_install_message:
154
+ rdoc_options: []
155
+ require_paths:
156
+ - lib
157
+ required_ruby_version: !ruby/object:Gem::Requirement
158
+ requirements:
159
+ - - '='
160
+ - !ruby/object:Gem::Version
161
+ version: '2.3'
162
+ required_rubygems_version: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ requirements: []
168
+ rubygems_version: 3.2.3
169
+ signing_key:
170
+ specification_version: 4
171
+ summary: Configuration framework for Ruby.
172
+ test_files:
173
+ - spec/spec_helper.rb