ravioli 0.1.0 → 0.1.2

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