pry-byetypo 1.1.0 → 1.2.0
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 +4 -4
- data/Gemfile.lock +3 -3
- data/README.md +2 -2
- data/lib/pry-byetypo/exceptions/active_record/base.rb +2 -6
- data/lib/pry-byetypo/exceptions/{name_error → active_record}/uninitialized_constant.rb +4 -8
- data/lib/pry-byetypo/exceptions/exceptions_base.rb +5 -1
- data/lib/pry-byetypo/exceptions/name_error/handler.rb +2 -2
- data/lib/pry-byetypo/exceptions/name_error/undefined_variable.rb +2 -6
- data/lib/pry-byetypo/session/populate_history.rb +20 -6
- data/lib/pry-byetypo/setup/application_dictionary.rb +5 -57
- data/lib/pry-byetypo/setup/dictionary/active_record.rb +81 -0
- data/lib/pry-byetypo/setup/store.rb +9 -0
- data/lib/pry-byetypo/version.rb +1 -1
- data/pry-byetypo.gemspec +4 -4
- metadata +22 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dd76efc826578597fe9cecb0ec6357a275d8cb8c37aaa1e238681f0235287027
|
4
|
+
data.tar.gz: 11eeb72895ab4150815e61f932a7aa8d13dc2ae6d6b3564c81d3ff9624c8ec89
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9f55811aaaeeeb06521f50108d8fab819b00c461b2fd635519ad3559baf409ee256e241d5315a39ec2e238aaae6e330f2d84bcd0cfbc1b3b9f04e9b26d8b9d39
|
7
|
+
data.tar.gz: 954ecd0a20d6fb34df1592cf36f8c2dd5d893d21f0060a7ccba7a4769ead0800917d6ee08aa8c294b8937e8eaa450c77fe7ac3704f4da3e2ea4466257e306552
|
data/Gemfile.lock
CHANGED
@@ -1,10 +1,9 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
pry-byetypo (1.
|
4
|
+
pry-byetypo (1.2.0)
|
5
5
|
colorize (~> 1.1.0)
|
6
6
|
pry (>= 0.13, < 0.15)
|
7
|
-
rails (~> 7.0)
|
8
7
|
|
9
8
|
GEM
|
10
9
|
remote: https://rubygems.org/
|
@@ -146,7 +145,7 @@ GEM
|
|
146
145
|
psych (5.1.2)
|
147
146
|
stringio
|
148
147
|
racc (1.7.3)
|
149
|
-
rack (3.0.
|
148
|
+
rack (3.0.9)
|
150
149
|
rack-session (2.0.0)
|
151
150
|
rack (>= 3.0.0)
|
152
151
|
rack-test (2.1.0)
|
@@ -253,6 +252,7 @@ PLATFORMS
|
|
253
252
|
DEPENDENCIES
|
254
253
|
byebug
|
255
254
|
pry-byetypo!
|
255
|
+
rails (~> 7.0)
|
256
256
|
rake (~> 13.0)
|
257
257
|
rspec (~> 3.0)
|
258
258
|
standard (~> 1.3)
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# PRY-BYETYPO
|
1
|
+
# PRY-BYETYPO 👋
|
2
2
|
|
3
3
|
Autocorrects typos in your Pry console.
|
4
4
|
|
@@ -26,7 +26,7 @@ I, [2024-01-31T17:11:16.344503 #3739] INFO -- : Running: result
|
|
26
26
|
```
|
27
27
|
|
28
28
|
> [!NOTE]
|
29
|
-
>
|
29
|
+
> Currently, this plugin is not truly ORM-agnostic; to fully benefit from it, ActiveRecord is required.
|
30
30
|
|
31
31
|
## Installation
|
32
32
|
|
@@ -7,10 +7,6 @@ module Exceptions
|
|
7
7
|
class Base < ExceptionsBase
|
8
8
|
private
|
9
9
|
|
10
|
-
def corrected_word
|
11
|
-
@corrected_word ||= spell_checker(associations_dictionary).correct(unknown_from_exception).first
|
12
|
-
end
|
13
|
-
|
14
10
|
def corrected_cmd
|
15
11
|
@corrected_cmd ||= last_cmd.gsub(/\b#{unknown_from_exception}\b/, corrected_word)
|
16
12
|
end
|
@@ -19,8 +15,8 @@ module Exceptions
|
|
19
15
|
exception.to_s.match(exception_regexp)[1]
|
20
16
|
end
|
21
17
|
|
22
|
-
def
|
23
|
-
|
18
|
+
def dictionary
|
19
|
+
store.transaction { |s| s["associations"] }
|
24
20
|
end
|
25
21
|
end
|
26
22
|
end
|
@@ -1,25 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "
|
3
|
+
require_relative "base"
|
4
4
|
|
5
5
|
module Exceptions
|
6
|
-
module
|
7
|
-
class UninitializedConstant <
|
6
|
+
module ActiveRecord
|
7
|
+
class UninitializedConstant < Base
|
8
8
|
private
|
9
9
|
|
10
10
|
def unknown_from_exception
|
11
11
|
exception.to_s.split.last
|
12
12
|
end
|
13
13
|
|
14
|
-
def corrected_word
|
15
|
-
@corrected_word ||= spell_checker(ar_models_dictionary).correct(unknown_from_exception).first
|
16
|
-
end
|
17
|
-
|
18
14
|
def corrected_cmd
|
19
15
|
@corrected_cmd ||= last_cmd.gsub(unknown_from_exception, corrected_word)
|
20
16
|
end
|
21
17
|
|
22
|
-
def
|
18
|
+
def dictionary
|
23
19
|
@ar_models_dictionary ||= store.transaction { |s| s["active_record_models"] }
|
24
20
|
end
|
25
21
|
end
|
@@ -29,7 +29,11 @@ class ExceptionsBase < Base
|
|
29
29
|
@pry = pry
|
30
30
|
end
|
31
31
|
|
32
|
-
def
|
32
|
+
def corrected_word
|
33
|
+
@corrected_word ||= spell_checker.correct(unknown_from_exception).first
|
34
|
+
end
|
35
|
+
|
36
|
+
def spell_checker
|
33
37
|
DidYouMean::SpellChecker.new(dictionary: dictionary)
|
34
38
|
end
|
35
39
|
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require_relative "../exceptions_base"
|
4
4
|
require_relative "../../constants/errors"
|
5
|
-
require_relative "uninitialized_constant"
|
5
|
+
require_relative "../active_record/uninitialized_constant"
|
6
6
|
require_relative "undefined_variable"
|
7
7
|
|
8
8
|
module Exceptions
|
@@ -21,7 +21,7 @@ module Exceptions
|
|
21
21
|
def call
|
22
22
|
case exception.message
|
23
23
|
in /#{Constants::Errors::UNINITIALIZED_CONSTANT}/
|
24
|
-
UninitializedConstant.call(output, exception, pry)
|
24
|
+
ActiveRecord::UninitializedConstant.call(output, exception, pry)
|
25
25
|
in /#{Constants::Errors::UNDEFINED_VARIABLE}/
|
26
26
|
UndefinedVariable.call(output, exception, pry)
|
27
27
|
else
|
@@ -7,10 +7,6 @@ module Exceptions
|
|
7
7
|
class UndefinedVariable < ExceptionsBase
|
8
8
|
private
|
9
9
|
|
10
|
-
def corrected_word
|
11
|
-
@corrected_word ||= spell_checker(session_dictionary).correct(unknown_from_exception).first
|
12
|
-
end
|
13
|
-
|
14
10
|
def corrected_cmd
|
15
11
|
@corrected_cmd ||= last_cmd.gsub(/\b#{unknown_from_exception}\b/, corrected_word)
|
16
12
|
end
|
@@ -19,8 +15,8 @@ module Exceptions
|
|
19
15
|
exception.to_s.match(exception_regexp)[1]
|
20
16
|
end
|
21
17
|
|
22
|
-
def
|
23
|
-
|
18
|
+
def dictionary
|
19
|
+
store.transaction { |s| s[pry_instance_uid] }
|
24
20
|
end
|
25
21
|
|
26
22
|
def exception_regexp
|
@@ -14,10 +14,12 @@ module Session
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def call
|
17
|
+
return unless is_assignement_variables?
|
18
|
+
|
17
19
|
store.transaction do
|
18
|
-
store.abort unless
|
20
|
+
store.abort unless variables_to_store
|
19
21
|
|
20
|
-
store[pry_instance_uid].push(
|
22
|
+
store[pry_instance_uid].push(*variables_to_store)
|
21
23
|
end
|
22
24
|
end
|
23
25
|
|
@@ -28,16 +30,28 @@ module Session
|
|
28
30
|
binding.binding_stack.join
|
29
31
|
end
|
30
32
|
|
31
|
-
def
|
32
|
-
@
|
33
|
+
def variables_to_store
|
34
|
+
@variables_to_store ||= last_cmd.split("=").first.strip.split(",")
|
33
35
|
end
|
34
36
|
|
35
37
|
def last_cmd
|
36
38
|
binding.eval_string.strip
|
37
39
|
end
|
38
40
|
|
39
|
-
|
40
|
-
|
41
|
+
# Returns true if the last command seems to be an assignment of variables, false otherwise.
|
42
|
+
#
|
43
|
+
# Examples
|
44
|
+
#
|
45
|
+
# is_assignment_variables?("user_last, user_first = User.last, User.first")
|
46
|
+
# # => true
|
47
|
+
#
|
48
|
+
# is_assignment_variables?("user_last = User.last")
|
49
|
+
# # => true
|
50
|
+
#
|
51
|
+
# is_assignment_variables?("user_last")
|
52
|
+
# # => false
|
53
|
+
def is_assignement_variables?
|
54
|
+
last_cmd.include?("=")
|
41
55
|
end
|
42
56
|
end
|
43
57
|
end
|
@@ -1,10 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "checks/database_url"
|
4
|
-
require_relative "checks/database_pool"
|
5
|
-
require_relative "store"
|
6
3
|
require_relative "../base"
|
7
|
-
|
4
|
+
require_relative "store"
|
5
|
+
require_relative "dictionary/active_record"
|
8
6
|
require "pstore"
|
9
7
|
|
10
8
|
module Setup
|
@@ -16,7 +14,7 @@ module Setup
|
|
16
14
|
end
|
17
15
|
|
18
16
|
def call
|
19
|
-
|
17
|
+
Setup::Dictionary::ActiveRecord.initialize! if defined?(ActiveRecord)
|
20
18
|
populate_store
|
21
19
|
end
|
22
20
|
|
@@ -24,64 +22,14 @@ module Setup
|
|
24
22
|
|
25
23
|
attr_reader :binding
|
26
24
|
|
27
|
-
SEVEN_DAYS = 604800
|
28
|
-
|
29
25
|
def populate_store
|
30
|
-
store.
|
31
|
-
|
32
|
-
store[pry_instance_uid] = []
|
33
|
-
store.commit unless staled_store?
|
34
|
-
|
35
|
-
store["active_record_models"] = populate_active_record_models_dictionary
|
36
|
-
store["associations"] = populate_associations
|
37
|
-
store["synced_at"] = Time.now
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def establish_db_connection
|
42
|
-
configuration_checks
|
43
|
-
ActiveRecord::Base.establish_connection(development_database_config)
|
44
|
-
end
|
45
|
-
|
46
|
-
def populate_active_record_models_dictionary
|
47
|
-
Zeitwerk::Loader.eager_load_all
|
48
|
-
ActiveRecord::Base.descendants.map { |model| model.name }
|
49
|
-
end
|
50
|
-
|
51
|
-
def populate_associations
|
52
|
-
table_names = ActiveRecord::Base.connection.tables
|
53
|
-
singularize_table_names = table_names.map { |a| a.chop }
|
54
|
-
table_names.zip(singularize_table_names).flatten
|
55
|
-
end
|
56
|
-
|
57
|
-
def configuration_checks
|
58
|
-
Setup::Checks::DatabaseUrl.check(development_database_config, logger)
|
59
|
-
Setup::Checks::DatabasePool.check(development_database_config, logger)
|
60
|
-
end
|
61
|
-
|
62
|
-
def database_config
|
63
|
-
YAML.safe_load(File.read("./config/database.yml"), aliases: true)
|
64
|
-
end
|
65
|
-
|
66
|
-
def development_database_config
|
67
|
-
@development_database_config ||= database_config["development"]
|
68
|
-
end
|
69
|
-
|
70
|
-
# By default we update the store every week.
|
71
|
-
# TODO: Make it configurable
|
72
|
-
def staled_store?
|
73
|
-
return true if store["synced_at"].nil?
|
74
|
-
|
75
|
-
(store["synced_at"] + SEVEN_DAYS) <= Time.now
|
26
|
+
# Create a table with unique instance identifier information to store variables history.
|
27
|
+
store.transaction { store[pry_instance_uid] = [] }
|
76
28
|
end
|
77
29
|
|
78
30
|
# Use the binding identifier as pry instance uid.
|
79
31
|
def pry_instance_uid
|
80
32
|
binding.to_s
|
81
33
|
end
|
82
|
-
|
83
|
-
def logger
|
84
|
-
@logger = Logger.new($stdout)
|
85
|
-
end
|
86
34
|
end
|
87
35
|
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../checks/database_url"
|
4
|
+
require_relative "../checks/database_pool"
|
5
|
+
require_relative "../store"
|
6
|
+
|
7
|
+
require "pstore"
|
8
|
+
|
9
|
+
module Setup
|
10
|
+
module Dictionary
|
11
|
+
class ActiveRecord
|
12
|
+
class << self
|
13
|
+
include Store
|
14
|
+
|
15
|
+
def initialize!
|
16
|
+
establish_db_connection
|
17
|
+
populate_store
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def populate_store
|
23
|
+
store.transaction do
|
24
|
+
store.commit unless staled_store?
|
25
|
+
|
26
|
+
store["active_record_models"] = populate_active_record_models_dictionary
|
27
|
+
store["associations"] = populate_associations
|
28
|
+
store["synced_at"] = Time.now
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def establish_db_connection
|
33
|
+
configuration_checks
|
34
|
+
::ActiveRecord::Base.establish_connection(development_database_config)
|
35
|
+
end
|
36
|
+
|
37
|
+
def populate_active_record_models_dictionary
|
38
|
+
Zeitwerk::Loader.eager_load_all
|
39
|
+
::ActiveRecord::Base.descendants.map { |model| format_active_record_model(model) }.flatten
|
40
|
+
end
|
41
|
+
|
42
|
+
def populate_associations
|
43
|
+
table_names = ::ActiveRecord::Base.connection.tables
|
44
|
+
singularize_table_names = table_names.map { |a| a.chop }
|
45
|
+
table_names.zip(singularize_table_names).flatten
|
46
|
+
end
|
47
|
+
|
48
|
+
# This method takes an ActiveRecord model as an argument and formats its name and module information.
|
49
|
+
# If the model is within a module namespace, it returns an array containing the model's name and an array of its modules.
|
50
|
+
# If the model is not within a module, it returns just the model's name as a string.
|
51
|
+
def format_active_record_model(model)
|
52
|
+
modules = model.name.split("::")
|
53
|
+
return model.name, modules if modules.count > 1
|
54
|
+
|
55
|
+
model.name
|
56
|
+
end
|
57
|
+
|
58
|
+
def development_database_config
|
59
|
+
@development_database_config ||= database_config["development"]
|
60
|
+
end
|
61
|
+
|
62
|
+
def configuration_checks
|
63
|
+
Setup::Checks::DatabaseUrl.check(development_database_config, logger)
|
64
|
+
Setup::Checks::DatabasePool.check(development_database_config, logger)
|
65
|
+
end
|
66
|
+
|
67
|
+
def database_config
|
68
|
+
YAML.safe_load(File.read(database_config_path), aliases: true)
|
69
|
+
end
|
70
|
+
|
71
|
+
def logger
|
72
|
+
@logger = Logger.new($stdout)
|
73
|
+
end
|
74
|
+
|
75
|
+
def database_config_path
|
76
|
+
ENV["DB_CONFIG_PATH"] || "./config/database.yml"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module Setup
|
2
2
|
module Store
|
3
3
|
DEFAULT_STORE_PATH = "byetypo_dictionary.pstore"
|
4
|
+
SEVEN_DAYS = 604800
|
4
5
|
|
5
6
|
def store
|
6
7
|
@store ||= PStore.new(store_path)
|
@@ -9,5 +10,13 @@ module Setup
|
|
9
10
|
def store_path
|
10
11
|
ENV["BYETYPO_STORE_PATH"] || DEFAULT_STORE_PATH
|
11
12
|
end
|
13
|
+
|
14
|
+
# By default we update the store every week.
|
15
|
+
# TODO: Make it configurable
|
16
|
+
def staled_store?
|
17
|
+
return true if store["synced_at"].nil?
|
18
|
+
|
19
|
+
(store["synced_at"] + SEVEN_DAYS) <= Time.now
|
20
|
+
end
|
12
21
|
end
|
13
22
|
end
|
data/lib/pry-byetypo/version.rb
CHANGED
data/pry-byetypo.gemspec
CHANGED
@@ -5,14 +5,14 @@ require_relative "lib/pry-byetypo/version"
|
|
5
5
|
Gem::Specification.new do |gem|
|
6
6
|
gem.name = "pry-byetypo"
|
7
7
|
gem.version = Pry::Byetypo::VERSION
|
8
|
-
gem.authors = ["
|
8
|
+
gem.authors = ["Clément Morisset"]
|
9
9
|
gem.email = ["morissetcl87@gmail.com"]
|
10
10
|
|
11
11
|
gem.summary = "Autocorrects typos in your Pry console"
|
12
|
-
gem.description = "This
|
12
|
+
gem.description = "This Pry plugin captures exceptions that could be due to typos and deduces the correct command based on your database information."
|
13
13
|
gem.homepage = "https://github.com/morissetcl/pry-byetypo"
|
14
14
|
gem.license = "MIT"
|
15
|
-
gem.required_ruby_version = ">= 2.
|
15
|
+
gem.required_ruby_version = ">= 2.7.0"
|
16
16
|
|
17
17
|
gem.metadata["homepage_uri"] = gem.homepage
|
18
18
|
gem.metadata["source_code_uri"] = "https://github.com/morissetcl/pry-byetypo"
|
@@ -28,7 +28,7 @@ Gem::Specification.new do |gem|
|
|
28
28
|
gem.bindir = "exe"
|
29
29
|
gem.executables = gem.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
30
30
|
gem.require_paths = ["lib"]
|
31
|
+
gem.add_development_dependency "rails", "~> 7.0"
|
31
32
|
gem.add_runtime_dependency "colorize", "~> 1.1.0"
|
32
33
|
gem.add_runtime_dependency "pry", ">= 0.13", "< 0.15"
|
33
|
-
gem.add_runtime_dependency "rails", "~> 7.0"
|
34
34
|
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pry-byetypo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
7
|
+
- Clément Morisset
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-02-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '7.0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '7.0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: colorize
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -44,22 +58,8 @@ dependencies:
|
|
44
58
|
- - "<"
|
45
59
|
- !ruby/object:Gem::Version
|
46
60
|
version: '0.15'
|
47
|
-
|
48
|
-
|
49
|
-
requirement: !ruby/object:Gem::Requirement
|
50
|
-
requirements:
|
51
|
-
- - "~>"
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
version: '7.0'
|
54
|
-
type: :runtime
|
55
|
-
prerelease: false
|
56
|
-
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
requirements:
|
58
|
-
- - "~>"
|
59
|
-
- !ruby/object:Gem::Version
|
60
|
-
version: '7.0'
|
61
|
-
description: This small Pry plugin captures exceptions that could be due to typos
|
62
|
-
and deduces the correct command based on your database information.
|
61
|
+
description: This Pry plugin captures exceptions that could be due to typos and deduces
|
62
|
+
the correct command based on your database information.
|
63
63
|
email:
|
64
64
|
- morissetcl87@gmail.com
|
65
65
|
executables: []
|
@@ -81,10 +81,10 @@ files:
|
|
81
81
|
- lib/pry-byetypo/exceptions/active_record/base.rb
|
82
82
|
- lib/pry-byetypo/exceptions/active_record/configuration_error.rb
|
83
83
|
- lib/pry-byetypo/exceptions/active_record/statement_invalid.rb
|
84
|
+
- lib/pry-byetypo/exceptions/active_record/uninitialized_constant.rb
|
84
85
|
- lib/pry-byetypo/exceptions/exceptions_base.rb
|
85
86
|
- lib/pry-byetypo/exceptions/name_error/handler.rb
|
86
87
|
- lib/pry-byetypo/exceptions/name_error/undefined_variable.rb
|
87
|
-
- lib/pry-byetypo/exceptions/name_error/uninitialized_constant.rb
|
88
88
|
- lib/pry-byetypo/exceptions_handler.rb
|
89
89
|
- lib/pry-byetypo/session/clear_history.rb
|
90
90
|
- lib/pry-byetypo/session/populate_history.rb
|
@@ -92,6 +92,7 @@ files:
|
|
92
92
|
- lib/pry-byetypo/setup/checks/base.rb
|
93
93
|
- lib/pry-byetypo/setup/checks/database_pool.rb
|
94
94
|
- lib/pry-byetypo/setup/checks/database_url.rb
|
95
|
+
- lib/pry-byetypo/setup/dictionary/active_record.rb
|
95
96
|
- lib/pry-byetypo/setup/store.rb
|
96
97
|
- lib/pry-byetypo/version.rb
|
97
98
|
- pry-byetypo.gemspec
|
@@ -111,7 +112,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
111
112
|
requirements:
|
112
113
|
- - ">="
|
113
114
|
- !ruby/object:Gem::Version
|
114
|
-
version: 2.
|
115
|
+
version: 2.7.0
|
115
116
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
116
117
|
requirements:
|
117
118
|
- - ">="
|