fig_tree 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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