ravioli 0.1.0 → 0.1.2

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: 10956034d9851d2c30cc00a73bbb95ece033cb8ca1d6bc66dee4ad106335b430
4
- data.tar.gz: 340b538b33f19016fbc494633ef809a79b1df518016af43de1c84f5428ce42fd
3
+ metadata.gz: 92bc88993084463bb740d10f3b95d4282c083e492db56deb6326c37718cc6f94
4
+ data.tar.gz: 077a5e8070664163c4f8508a9c2e1d7850d8241a4c96ad3b58a716ec9f0b98f2
5
5
  SHA512:
6
- metadata.gz: e639d69ce9ccd5e373805b8e06edc8d2e5a468af695ce40dc6630cafbfe2d8ae403fe63cda38ba61b6d6b8becdbdca846566d6f5aea374a4ae9905ae66527d74
7
- data.tar.gz: f71dd8b25999a8972fc3ac9173c488ce337233f5f2496dcdb084c59067ea48056026ac65d9f1a8f176aac52c5eca9b5c71b6202998ebc40761bb6ff0064c491e
6
+ metadata.gz: ba40d1bbfc6a08e842577f746a7ac21b17aaa94824dfe0dcd1b6aa86b23868f99bcad55c05a5bcb8dff1448249bf6ca797e84a54eec1f8004cc47be4c57a5019
7
+ data.tar.gz: 6cb087130e095129930d2ec12d0b9505adae10e0d8838cd60d06db5b61ca6d3d3b164fcc1a2f8299b65be5083d2479b39693c9ceb9d5540b05a398d6826129c0
data/README.md CHANGED
@@ -35,7 +35,7 @@ key = Rails.config.dig!(:thing, :api_key)
35
35
  -->
36
36
  1. Add `gem "ravioli"` to your `Gemfile`
37
37
  2. Run `bundle install`
38
- 3. Add an initializer (totally optional): `rails generate ravioli:install` - Ravioli will do **everything** automatically for you if you skip this step, because I aim to *please*
38
+ 3. Add an initializer (totally optional): `rails generate ravioli:install` - Ravioli will do **everything** automatically for you if you skip this step, because I'm here to put a little meat on your bones.
39
39
 
40
40
  ## Usage
41
41
 
@@ -207,7 +207,7 @@ mailjet:
207
207
  # ...the contents of mailjet.json
208
208
  ```
209
209
 
210
- **NOTE THAT APP.YML GOT LOADED INTO THE ROOT OF THE CONFIGURATION!** This is because the automatic loading system assumes you want some configuration values that aren't nested. It effectively calls [`load_configuration_file(filename, key: File.basename(filename) != "app")`](#load_configuration_file), which ensures that, for example, the values in `config/mailjet.json` get loaded under `Rails.config.mailjet` while the valuaes in `config/app.yml` get loaded directly into `Rails.config`.
210
+ **NOTE THAT APP.YML GOT LOADED INTO THE ROOT OF THE CONFIGURATION!** This is because the automatic loading system assumes you want some configuration values that aren't nested. It effectively calls [`load_file(filename, key: File.basename(filename) != "app")`](#load_file), which ensures that, for example, the values in `config/mailjet.json` get loaded under `Rails.config.mailjet` while the valuaes in `config/app.yml` get loaded directly into `Rails.config`.
211
211
 
212
212
  ### 3. Loads and combines encrypted credentials
213
213
 
@@ -225,7 +225,7 @@ This allows you to use your secure credentials stores without duplicating inform
225
225
  def Rails.config
226
226
  @config ||= Ravioli.build(strict: Rails.env.production?) do |config|
227
227
  config.add_staging_flag!
228
- config.auto_load_config_files!
228
+ config.auto_load_files!
229
229
  config.auto_load_credentials!
230
230
  end
231
231
  end
@@ -243,16 +243,16 @@ The best way to build your own configuration is by calling `Ravioli.build`. It w
243
243
 
244
244
  ```ruby
245
245
  configuration = Ravioli.build do |config|
246
- config.load_configuration_file("whatever.yml")
246
+ config.load_file("things.yml")
247
247
  config.whatever = {things: true}
248
248
  end
249
249
  ```
250
250
 
251
- This will yield a configured instance of `Ravioli::Configuration` with structure
251
+ This will return a configured instance of `Ravioli::Configuration` with structure
252
252
 
253
253
  ```yaml
254
- rubocop:
255
- # ...the contents of whatever.yml
254
+ things:
255
+ # ...the contents of things.yml
256
256
  whatever:
257
257
  things: true
258
258
  ```
@@ -303,7 +303,7 @@ end
303
303
  ### `add_staging_flag!`
304
304
 
305
305
 
306
- ### `load_config_file`
306
+ ### `load_file`
307
307
 
308
308
  Let's imagine we have this config file:
309
309
 
@@ -329,24 +329,24 @@ In an initializer, generate your Ravioli instance and load it up:
329
329
  ```ruby
330
330
  # config/initializers/_ravioli.rb`
331
331
  Config = Ravioli.build do
332
- load_config_file(:mailjet) # given a symbol, it automatically assumes you meant `config/mailjet.yml`
333
- load_config_file("config/mailjet") # same as above
334
- load_config_file("lib/mailjet/config") # looks for `Rails.root.join("lib", "mailjet", "config.yml")
332
+ load_file(:mailjet) # given a symbol, it automatically assumes you meant `config/mailjet.yml`
333
+ load_file("config/mailjet") # same as above
334
+ load_file("lib/mailjet/config") # looks for `Rails.root.join("lib", "mailjet", "config.yml")
335
335
  end
336
336
  ```
337
337
 
338
338
  `config/initializers/_ravioli.rb`
339
339
 
340
340
  ```ruby
341
- Config = Ravioli.build do
341
+ Config = Ravioli.build do |config|
342
342
  %i[new_relic sentry google].each do |service|
343
- load_config_file(service)
343
+ config.load_file(service)
344
344
  end
345
345
 
346
- load_credentials # just load the base credentials file
347
- load_credentials("credentials/production") if Rails.env.production? # add production overrides when appropriate
346
+ config.load_credentials # just load the base credentials file
347
+ config.load_credentials("credentials/production") if Rails.env.production? # add production overrides when appropriate
348
348
 
349
- self.staging = File.exists?("./staging.txt") # technically you could do this ... I don't know why you would, but technically you could
349
+ config.staging = File.exists?("./staging.txt") # technically you could do this ... I don't know why you would, but technically you could
350
350
  end
351
351
  ```
352
352
 
data/lib/ravioli.rb CHANGED
@@ -7,28 +7,36 @@ require_relative "ravioli/builder"
7
7
  require_relative "ravioli/configuration"
8
8
  require_relative "ravioli/version"
9
9
 
10
- ##
11
- # Ravioli contains helper methods for building Configuration instances and accessing them, as well
12
- # as the Builder class for help loading configuration files and encrypted credentials
10
+ # The root namespace for all of Ravioli, and owner of two handly
11
+ # configuration-related class methods
13
12
  module Ravioli
14
- NAME = "Ravioli"
15
-
16
13
  class << self
17
- def build(class_name: "Configuration", namespace: nil, strict: false, &block)
18
- builder = Builder.new(class_name: class_name, namespace: namespace, strict: strict)
19
- yield builder if block_given?
20
- builder.build!.tap do |configuration|
21
- configurations.push(configuration)
22
- end
23
- end
24
-
25
- def default
26
- configurations.last
14
+ # Forwards arguments to a {Ravioli::Builder}. See
15
+ # {Ravioli::Builder#new} for complete documentation.
16
+ #
17
+ # @param namespace [String, Module, Class] the name of, or a direct reference to, the module or class your Configuration class should namespace itself within
18
+ # @param class_name [String] the name of the namespace's Configuration class
19
+ # @param strict [boolean] whether or not the Builder instance should throw errors when there are errors loading configuration files or encrypted credentials
20
+ def build(namespace: nil, class_name: "Configuration", strict: false, &block)
21
+ builder = Builder.new(
22
+ class_name: class_name,
23
+ hijack: true,
24
+ namespace: namespace,
25
+ strict: strict,
26
+ )
27
+ yield builder if block
28
+ builder.build!
27
29
  end
28
30
 
31
+ # Returns a list of all of the configuration instances
29
32
  def configurations
30
33
  @configurations ||= []
31
34
  end
35
+
36
+ # Returns the most-recently configured Ravioli instance that has been built with {Ravioli::build}.
37
+ def default
38
+ configurations.last
39
+ end
32
40
  end
33
41
  end
34
42
 
@@ -1,18 +1,60 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/all"
4
+ require "erb"
4
5
  require_relative "configuration"
5
6
 
6
7
  module Ravioli
7
- # The Builder clas provides a simple interface for building a Ravioli configuration. It has
8
+ # The Builder class provides a simple interface for building a Ravioli configuration. It has
8
9
  # methods for loading configuration files and encrypted credentials, and forwards direct
9
10
  # configuration on to the configuration instance. This allows us to keep a clean separation of
10
11
  # concerns (builder: loads configuration details; configuration: provides access to information
11
12
  # in memory).
13
+ #
14
+ # == ENV variables and encrypted credentials keys
15
+ #
16
+ # <table><thead><tr><th>File</th><th>First it tries...</th><th>Then it tries...</th></tr></thead><tbody><tr><td>
17
+ #
18
+ # `config/credentials.yml.enc`
19
+ #
20
+ # </td><td>
21
+ #
22
+ # `ENV["RAILS_BASE_KEY"]`
23
+ #
24
+ # </td><td>
25
+ #
26
+ # `ENV["RAILS_MASTER_KEY"]`
27
+ #
28
+ # </td></tr><tr><td>
29
+ #
30
+ # `config/credentials/production.yml.enc`
31
+
32
+ # </td><td>
33
+ #
34
+ # `ENV["RAILS_PRODUCTION_KEY"]`
35
+ #
36
+ # </td><td>
37
+ #
38
+ # `ENV["RAILS_MASTER_KEY"]`
39
+ #
40
+ # </td></tr><tr><td>
41
+ #
42
+ # `config/credentials/staging.yml.enc` (only if running on staging)
43
+ #
44
+ # </td><td>
45
+ #
46
+ # `ENV["RAILS_STAGING_KEY"]`
47
+ #
48
+ # </td><td>
49
+ #
50
+ # `ENV["RAILS_MASTER_KEY"]`
51
+ #
52
+ # </td></tr></tbody></table>
12
53
  class Builder
13
- def initialize(class_name: "Configuration", namespace: nil, strict: false)
54
+ def initialize(class_name: "Configuration", hijack: false, namespace: nil, strict: false)
14
55
  configuration_class = if namespace.present?
15
56
  namespace.class_eval <<-EOC, __FILE__, __LINE__ + 1
57
+ # class Configuration < Ravioli::Configuration; end
16
58
  class #{class_name.to_s.classify} < Ravioli::Configuration; end
17
59
  EOC
18
60
  namespace.const_get(class_name)
@@ -21,10 +63,23 @@ module Ravioli
21
63
  end
22
64
  @strict = !!strict
23
65
  @configuration = configuration_class.new
66
+ @reload_credentials = Set.new
67
+ @reload_paths = Set.new
68
+ @hijack = !!hijack
69
+
70
+ if @hijack
71
+ # Put this builder on the configurations stack - it will intercept setters on the underyling
72
+ # configuration object as it loads files, and mark those files as needing a reload once
73
+ # loading is complete
74
+ Ravioli.configurations.push(self)
75
+ end
24
76
  end
25
77
 
26
- # Automatically infer a `staging?` status
78
+ # Automatically infer a `staging` status from the current environment
79
+ #
80
+ # @param is_staging [boolean, #present?] whether or not the current environment is considered a staging environment
27
81
  def add_staging_flag!(is_staging = Rails.env.production? && ENV["STAGING"].present?)
82
+ is_staging = is_staging.present?
28
83
  configuration.staging = is_staging
29
84
  Rails.env.class_eval <<-EOC, __FILE__, __LINE__ + 1
30
85
  def staging?
@@ -37,15 +92,17 @@ module Ravioli
37
92
  is_staging
38
93
  end
39
94
 
40
- # Load YAML or JSON files in config/**/* (except for locales)
41
- def auto_load_config_files!
95
+ # Iterates through the config directory (including nested folders) and
96
+ # calls {Ravioli::Builder::load_file} on each JSON or YAML file it
97
+ # finds. Ignores `config/locales`.
98
+ def auto_load_files!
42
99
  config_dir = Rails.root.join("config")
43
100
  Dir[config_dir.join("{[!locales/]**/*,*}.{json,yaml,yml}")].each do |config_file|
44
- load_config_file(config_file, key: !File.basename(config_file, File.extname(config_file)).casecmp("app").zero?)
101
+ auto_load_file(config_file)
45
102
  end
46
103
  end
47
104
 
48
- # Load config/credentials**/*.yml.enc files (assuming we can find a key)
105
+ # Loads Rails encrypted credentials that it can. Checks for corresponding private key files, or ENV vars based on the {Ravioli::Builder credentials preadmlogic}
49
106
  def auto_load_credentials!
50
107
  # Load the base config
51
108
  load_credentials(key_path: "config/master.key", env_name: "base")
@@ -59,11 +116,23 @@ module Ravioli
59
116
 
60
117
  # When the builder is done working, lock the configuration and return it
61
118
  def build!
119
+ if @hijack
120
+ # Replace this builder with the underlying configuration on the configurations stack...
121
+ Ravioli.configurations.delete(self)
122
+ Ravioli.configurations.push(configuration)
123
+
124
+ # ...and then reload any config file that referenced the configuration the first time it was
125
+ # loaded!
126
+ @reload_paths.each do |path|
127
+ auto_load_file(path)
128
+ end
129
+ end
130
+
62
131
  configuration.freeze
63
132
  end
64
133
 
65
- # Load a config file either with a given path or by name (e.g. `config/whatever.yml` or `:whatever`)
66
- def load_config_file(path, options = {})
134
+ # Load a file either with a given path or by name (e.g. `config/whatever.yml` or `:whatever`)
135
+ def load_file(path, options = {})
67
136
  config = parse_config_file(path, options)
68
137
  configuration.append(config) if config.present?
69
138
  rescue => error
@@ -75,7 +144,7 @@ module Ravioli
75
144
  credentials = parse_credentials(path, env_name: env_name, key_path: key_path)
76
145
  configuration.append(credentials) if credentials.present?
77
146
  rescue => error
78
- warn "Could not decrypt `#{path}.yml.enc' with key file `#{key_path}' or `ENV[\"#{env_name}\"]'", error
147
+ warn "Could not decrypt `#{path}.yml.enc' with key file `#{key_path}' or `ENV[\"#{env_name}\"]'", error, critical: false
79
148
  {}
80
149
  end
81
150
 
@@ -86,6 +155,13 @@ module Ravioli
86
155
 
87
156
  attr_reader :configuration
88
157
 
158
+ def auto_load_file(config_file)
159
+ basename = File.basename(config_file, File.extname(config_file))
160
+ dirname = File.dirname(config_file)
161
+ key = %w[app application].exclude?(basename) && dirname != config_dir
162
+ load_file(config_file, key: key)
163
+ end
164
+
89
165
  def extract_environmental_config(config)
90
166
  # Check if the config hash is keyed by environment - if not, just return it as-is. It's
91
167
  # considered "keyed by environment" if it contains ONLY env-specific keys.
@@ -105,12 +181,23 @@ module Ravioli
105
181
  # rubocop:disable Style/MethodMissingSuper
106
182
  # rubocop:disable Style/MissingRespondToMissing
107
183
  def method_missing(*args, &block)
184
+ if @current_path
185
+ @reload_paths.add(@current_path)
186
+ end
187
+
188
+ if @current_credentials
189
+ @reload_credentials.add(@current_credentials)
190
+ end
191
+
108
192
  configuration.send(*args, &block)
109
193
  end
110
194
  # rubocop:enable Style/MissingRespondToMissing
111
195
  # rubocop:enable Style/MethodMissingSuper
112
196
 
113
197
  def parse_config_file(path, options = {})
198
+ # Stash a reference to the file we're parsing, so we can reload it later if it tries to use
199
+ # the configuration object
200
+ @current_path = path
114
201
  path = path_to_config_file_path(path)
115
202
 
116
203
  config = case path.extname.downcase
@@ -119,9 +206,11 @@ module Ravioli
119
206
  when ".yml", ".yaml"
120
207
  parse_yaml_config_file(path)
121
208
  else
122
- raise ParseError.new("#{Ravioli::NAME} doesn't know how to parse #{path}")
209
+ raise ParseError.new("Ravioli doesn't know how to parse #{path}")
123
210
  end
124
211
 
212
+ # We are no longer loading anything
213
+ @current_path = nil
125
214
  # At least expect a hash to be returned from the loaded config file
126
215
  return {} unless config.is_a?(Hash)
127
216
 
@@ -145,6 +234,7 @@ module Ravioli
145
234
  end
146
235
 
147
236
  def parse_credentials(path, key_path: path, env_name: path.split("/").last)
237
+ @current_credentials = path
148
238
  env_name = env_name.to_s
149
239
  env_name = "RAILS_#{env_name.upcase}_KEY" unless env_name.upcase == env_name
150
240
  key_path = path_to_config_file_path(key_path, extnames: "key", quiet: true)
@@ -152,8 +242,9 @@ module Ravioli
152
242
  options[:env_key] = ENV[env_name].present? ? env_name : SecureRandom.hex(6)
153
243
 
154
244
  path = path_to_config_file_path(path, extnames: "yml.enc")
155
- credentials = Rails.application.encrypted(path, options)&.config || {}
156
- credentials
245
+ (Rails.application.encrypted(path, **options)&.config || {}).tap do
246
+ @current_credentials = nil
247
+ end
157
248
  end
158
249
 
159
250
  def parse_json_config_file(path)
@@ -162,7 +253,6 @@ module Ravioli
162
253
  end
163
254
 
164
255
  def parse_yaml_config_file(path)
165
- require "erb"
166
256
  contents = File.read(path)
167
257
  erb = ERB.new(contents).tap { |renderer| renderer.filename = path.to_s }
168
258
  YAML.safe_load(erb.result, aliases: true)
@@ -192,10 +282,10 @@ module Ravioli
192
282
  path
193
283
  end
194
284
 
195
- def warn(message, error = $!)
196
- message = "[#{Ravioli::NAME}] #{message}"
285
+ def warn(message, error = $!, critical: true)
286
+ message = "[Ravioli] #{message}"
197
287
  message = "#{message}:\n\n#{error.cause.inspect}" if error&.cause.present?
198
- if @strict
288
+ if @strict && critical
199
289
  raise BuildError.new(message, error)
200
290
  else
201
291
  Rails.logger.warn(message) if defined? Rails
@@ -204,6 +294,7 @@ module Ravioli
204
294
  end
205
295
  end
206
296
 
297
+ # Error raised when Ravioli is in strict mode. Includes the original error for context.
207
298
  class BuildError < StandardError
208
299
  def initialize(message, cause = nil)
209
300
  super message
@@ -214,5 +305,7 @@ module Ravioli
214
305
  @cause || super
215
306
  end
216
307
  end
308
+
309
+ # Error raised when Ravioli encounters a problem parsing a file
217
310
  class ParseError < StandardError; end
218
311
  end
@@ -5,20 +5,17 @@ require "ostruct"
5
5
 
6
6
  module Ravioli
7
7
  class Configuration < OpenStruct
8
- attr_reader :key_path
9
-
10
8
  def initialize(attributes = {})
11
9
  super({})
12
10
  @key_path = attributes.delete(:key_path)
13
11
  append(attributes)
14
12
  end
15
13
 
16
- # def ==(other)
17
- # other = other.table if other.respond_to?(:table)
18
- # other == table
19
- # end
20
-
14
+ # Convert a hash to accessors and nested {Ravioli::Configuration} instances.
15
+ #
16
+ # @param [Hash, #each] key-value pairs to be converted to accessors
21
17
  def append(attributes = {})
18
+ return unless attributes.respond_to?(:each)
22
19
  attributes.each do |key, value|
23
20
  self[key.to_sym] = cast(key.to_sym, value)
24
21
  end
@@ -40,6 +37,10 @@ module Ravioli
40
37
  fetch(*keys) { raise KeyMissingError.new("Could not find value at key path #{keys.inspect}") }
41
38
  end
42
39
 
40
+ def delete(key)
41
+ table.delete(key.to_s)
42
+ end
43
+
43
44
  def fetch(*keys)
44
45
  dig(*keys) || yield
45
46
  end
@@ -54,6 +55,8 @@ module Ravioli
54
55
 
55
56
  private
56
57
 
58
+ attr_reader :key_path
59
+
57
60
  def build(keys, attributes = {})
58
61
  attributes[:key_path] = key_path_for(keys)
59
62
  child = self.class.new(attributes)
@@ -3,16 +3,18 @@
3
3
  module Ravioli
4
4
  class Engine < ::Rails::Engine
5
5
  # Bootstrap Ravioli onto the Rails app
6
- initializer "ravioli", before: "load_environment_config" do |app|
7
- Rails.extend Ravioli::Config unless Rails.respond_to?(:config)
6
+ initializer "ravioli", before: :load_environment_config do |app|
7
+ Rails.extend Ravioli::RailsConfig unless Rails.respond_to?(:config)
8
8
  end
9
9
  end
10
10
 
11
- module Config
11
+ private
12
+
13
+ module RailsConfig
12
14
  def config
13
15
  Ravioli.default || Ravioli.build(namespace: Rails.application&.class&.module_parent, strict: Rails.env.production?) do |config|
14
16
  config.add_staging_flag!
15
- config.auto_load_config_files!
17
+ config.auto_load_files!
16
18
  config.auto_load_credentials!
17
19
  end
18
20
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Ravioli
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.2"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ravioli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Flip Sasser
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-02-23 00:00:00.000000000 Z
11
+ date: 2021-05-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -30,6 +30,48 @@ dependencies:
30
30
  - - ">="
31
31
  - !ruby/object:Gem::Version
32
32
  version: 6.0.3.1
33
+ - !ruby/object:Gem::Dependency
34
+ name: guard
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ type: :development
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: guard-rspec
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ - !ruby/object:Gem::Dependency
62
+ name: guard-rubocop
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
33
75
  - !ruby/object:Gem::Dependency
34
76
  name: pry
35
77
  requirement: !ruby/object:Gem::Requirement
@@ -90,16 +132,16 @@ dependencies:
90
132
  name: rubocop
91
133
  requirement: !ruby/object:Gem::Requirement
92
134
  requirements:
93
- - - "~>"
135
+ - - ">="
94
136
  - !ruby/object:Gem::Version
95
- version: '0.8'
137
+ version: '1.0'
96
138
  type: :development
97
139
  prerelease: false
98
140
  version_requirements: !ruby/object:Gem::Requirement
99
141
  requirements:
100
- - - "~>"
142
+ - - ">="
101
143
  - !ruby/object:Gem::Version
102
- version: '0.8'
144
+ version: '1.0'
103
145
  - !ruby/object:Gem::Dependency
104
146
  name: rubocop-ordered_methods
105
147
  requirement: !ruby/object:Gem::Requirement
@@ -118,44 +160,44 @@ dependencies:
118
160
  name: rubocop-performance
119
161
  requirement: !ruby/object:Gem::Requirement
120
162
  requirements:
121
- - - "~>"
163
+ - - ">="
122
164
  - !ruby/object:Gem::Version
123
- version: 1.5.2
165
+ version: '1.5'
124
166
  type: :development
125
167
  prerelease: false
126
168
  version_requirements: !ruby/object:Gem::Requirement
127
169
  requirements:
128
- - - "~>"
170
+ - - ">="
129
171
  - !ruby/object:Gem::Version
130
- version: 1.5.2
172
+ version: '1.5'
131
173
  - !ruby/object:Gem::Dependency
132
174
  name: rubocop-rails
133
175
  requirement: !ruby/object:Gem::Requirement
134
176
  requirements:
135
- - - "~>"
177
+ - - ">="
136
178
  - !ruby/object:Gem::Version
137
- version: 2.5.2
179
+ version: 2.5.0
138
180
  type: :development
139
181
  prerelease: false
140
182
  version_requirements: !ruby/object:Gem::Requirement
141
183
  requirements:
142
- - - "~>"
184
+ - - ">="
143
185
  - !ruby/object:Gem::Version
144
- version: 2.5.2
186
+ version: 2.5.0
145
187
  - !ruby/object:Gem::Dependency
146
188
  name: rubocop-rspec
147
189
  requirement: !ruby/object:Gem::Requirement
148
190
  requirements:
149
- - - "~>"
191
+ - - ">="
150
192
  - !ruby/object:Gem::Version
151
- version: '1.39'
193
+ version: '2.0'
152
194
  type: :development
153
195
  prerelease: false
154
196
  version_requirements: !ruby/object:Gem::Requirement
155
197
  requirements:
156
- - - "~>"
198
+ - - ">="
157
199
  - !ruby/object:Gem::Version
158
- version: '1.39'
200
+ version: '2.0'
159
201
  - !ruby/object:Gem::Dependency
160
202
  name: simplecov
161
203
  requirement: !ruby/object:Gem::Requirement
@@ -190,14 +232,14 @@ dependencies:
190
232
  requirements:
191
233
  - - "~>"
192
234
  - !ruby/object:Gem::Version
193
- version: '0.4'
235
+ version: 0.13.0
194
236
  type: :development
195
237
  prerelease: false
196
238
  version_requirements: !ruby/object:Gem::Requirement
197
239
  requirements:
198
240
  - - "~>"
199
241
  - !ruby/object:Gem::Version
200
- version: '0.4'
242
+ version: 0.13.0
201
243
  - !ruby/object:Gem::Dependency
202
244
  name: yard
203
245
  requirement: !ruby/object:Gem::Requirement
@@ -236,7 +278,7 @@ licenses:
236
278
  metadata:
237
279
  homepage_uri: https://github.com/flipsasser/ravioli
238
280
  source_code_uri: https://github.com/flipsasser/ravioli
239
- post_install_message:
281
+ post_install_message:
240
282
  rdoc_options: []
241
283
  require_paths:
242
284
  - lib
@@ -244,15 +286,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
244
286
  requirements:
245
287
  - - ">="
246
288
  - !ruby/object:Gem::Version
247
- version: 2.3.0
289
+ version: 2.4.0
248
290
  required_rubygems_version: !ruby/object:Gem::Requirement
249
291
  requirements:
250
292
  - - ">="
251
293
  - !ruby/object:Gem::Version
252
294
  version: '0'
253
295
  requirements: []
254
- rubygems_version: 3.0.3
255
- signing_key:
296
+ rubygems_version: 3.2.3
297
+ signing_key:
256
298
  specification_version: 4
257
299
  summary: Grab a fork and twist all your configuration spaghetti into a single, delicious
258
300
  bundle