rbs_rails 0.6.0 → 0.7.0

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: 5dd350161bbcf1358c43fbda2fb5b42aa106b42a14f079a26e60338e9ccbae92
4
- data.tar.gz: b5a700311050c8500037f70be69d652c96bbf20ebc0334ad49d7c97964b977ec
3
+ metadata.gz: 82919f7e04d613a702ad6cadbff8df905f23b54bf7dbdae04122a5af5df09608
4
+ data.tar.gz: 7070d476fe7f15776eed7fa406c423f18ba54077b4293ccb6064c151c7a89754
5
5
  SHA512:
6
- metadata.gz: 414a6a9fa8feb585dbae5826c68e9043eedeb3b4e1c43d112efdcdcb61c10686d18dc76d57191c34f456ec43c36246cb4c096ceb59dba7cdf0bba4f10a5e4159
7
- data.tar.gz: da5d5c7f919d5b2dedfb596bb8e207210ee9a3391db6af13372cc976b57f3ba89ca4b8a19578847f538b4b6adfd547c634f261ac8e21030f2ec98dee3e15147e
6
+ metadata.gz: 92c046d0f404ff63fe86b3fab5bd92dd24731919827c5ee04330cecf26ae158608e4b0babc1097977ef5cddcbd9474983621d188b996cf264cb96a65142adf95
7
+ data.tar.gz: 947c7022e0e49010cdc0fbce0bd453993f3ba0bc3df1fb5d406bce94361c49f8d61044b95ba9fed901e6635a9476b4c699812f2334e5e36552552138baada338
@@ -0,0 +1,18 @@
1
+ name: CI
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ test:
7
+ strategy:
8
+ fail-fast: false
9
+ matrix:
10
+ ruby: [2.6, 2.7, '3.0']
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v2
14
+ - uses: ruby/setup-ruby@v1
15
+ with:
16
+ ruby-version: ${{ matrix.ruby }}
17
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
18
+ - run: bundle exec rake
@@ -1,3 +0,0 @@
1
- [submodule "gem_rbs"]
2
- path = gem_rbs
3
- url = https://github.com/ruby/gem_rbs.git
@@ -0,0 +1,8 @@
1
+ # Change log
2
+
3
+ ## master (unreleased)
4
+
5
+ ## 0.7.0 (2020-12-28)
6
+
7
+ * **[BREAKING]** Re-structure signature directory. [#86](https://github.com/pocke/rbs_rails/pull/86)
8
+ * Generate ActiveRecord models with namespaces and superclasses. [#87](https://github.com/pocke/rbs_rails/pull/87)
@@ -0,0 +1,94 @@
1
+ #!ruby
2
+
3
+ require 'net/http'
4
+ require 'json'
5
+ require 'securerandom'
6
+ require 'pathname'
7
+
8
+ TOKEN = ENV.fetch('GITHUB_ACCESS_TOKEN')
9
+ VERSION = "6.0.3.2"
10
+
11
+ def req(query)
12
+ http = Net::HTTP.new("api.github.com", 443)
13
+ http.use_ssl = true
14
+ header = {
15
+ "Authorization" => "Bearer #{TOKEN}",
16
+ 'Content-Type' => 'application/json',
17
+ 'User-Agent' => 'gem_rbs client',
18
+ }
19
+ resp = http.request_post('/graphql', JSON.generate(query), header)
20
+ JSON.parse(resp.body, symbolize_names: true).tap do |content|
21
+ raise content[:errors].inspect if content[:errors]
22
+ end
23
+ end
24
+
25
+ class QueryBuilder
26
+ attr_reader :variables
27
+
28
+ def initialize
29
+ @queries = []
30
+ @variables = {}
31
+ end
32
+
33
+ def add(query, variables)
34
+ query = query.dup
35
+ variables = variables.transform_keys do |key|
36
+ next key unless @variables.key?(key)
37
+
38
+ new_key = key + '_' + SecureRandom.hex(8)
39
+ query.gsub!(key, new_key)
40
+ new_key
41
+ end
42
+
43
+ @queries << query
44
+ @variables.merge!(variables)
45
+ end
46
+
47
+ def query
48
+ # TODO: variable type
49
+ "query(#{variables.keys.map { |v| "$#{v}: String!" }.join(',')}) { #{@queries.join("\n")} }"
50
+ end
51
+ end
52
+
53
+ gems = %w[activesupport actionpack activejob activemodel actionview activerecord railties]
54
+
55
+ builder = QueryBuilder.new
56
+ gems.each do |gem|
57
+ path = "main:gems/#{gem}/#{VERSION}"
58
+ builder.add(<<~GRAPHQL, { 'path' => path })
59
+ #{gem}:repository(owner: "ruby", name: "gem_rbs") {
60
+ object(expression: $path) {
61
+ ... on Tree {
62
+ entries {
63
+ name
64
+ object {
65
+ ... on Blob {
66
+ isTruncated
67
+ text
68
+ }
69
+ }
70
+ }
71
+ }
72
+ }
73
+ }
74
+ GRAPHQL
75
+ end
76
+
77
+ resp = req(query: builder.query, variables: builder.variables)
78
+
79
+ resp[:data].each do |gem_name, gem_value|
80
+ gem_value.dig(:object, :entries).each do |entry|
81
+ fname = entry[:name]
82
+ if fname.end_with?('.rbs')
83
+ content =
84
+ if entry.dig(:object, :isTruncated)
85
+ `curl -H 'Accept: application/vnd.github.v3.raw' -H Authorization: token #{TOKEN} https://api.github.com/repos/ruby/gem_rbs/contents/gems/#{gem_name}/#{VERSION}/#{fname}`
86
+ else
87
+ entry.dig(:object, :text)
88
+ end
89
+ dir = Pathname("gem_rbs/gems/#{gem_name}/#{VERSION}")
90
+ dir.mkpath
91
+ dir.join(fname).write(content)
92
+ end
93
+ end
94
+ end
@@ -1,8 +1,12 @@
1
1
  require 'parser/current'
2
+ require 'rbs'
3
+ require 'stringio'
2
4
 
3
5
  require_relative "rbs_rails/version"
6
+ require_relative "rbs_rails/util"
4
7
  require_relative 'rbs_rails/active_record'
5
8
  require_relative 'rbs_rails/path_helpers'
9
+ require_relative 'rbs_rails/dependency_builder'
6
10
 
7
11
  module RbsRails
8
12
  class Error < StandardError; end
@@ -1,59 +1,84 @@
1
1
  module RbsRails
2
2
  module ActiveRecord
3
- def self.class_to_rbs(klass)
4
- Generator.new(klass).generate
3
+
4
+ def self.class_to_rbs(klass, dependencies: [])
5
+ Generator.new(klass, dependencies: dependencies).generate
5
6
  end
6
7
 
7
8
  class Generator
8
- def initialize(klass)
9
+ def initialize(klass, dependencies:)
9
10
  @klass = klass
11
+ @dependencies = dependencies
12
+ @klass_name = Util.module_name(klass)
13
+
14
+ namespaces = klass_name.split('::').tap{ |names| names.pop }
15
+ @dependencies << namespaces.join('::') unless namespaces.empty?
10
16
  end
11
17
 
12
18
  def generate
13
- [
14
- klass_decl,
15
- relation_decl,
16
- collection_proxy_decl,
17
- ].join("\n")
19
+ Util.format_rbs klass_decl
18
20
  end
19
21
 
20
22
  private def klass_decl
21
23
  <<~RBS
22
24
  #{header}
23
- extend _ActiveRecord_Relation_ClassMethods[#{klass.name}, #{relation_class_name}]
25
+ extend _ActiveRecord_Relation_ClassMethods[#{klass_name}, #{relation_class_name}]
24
26
 
25
- #{columns.indent(2)}
26
- #{associations.indent(2)}
27
- #{enum_instance_methods.indent(2)}
28
- #{enum_scope_methods(singleton: true).indent(2)}
29
- #{scopes(singleton: true).indent(2)}
30
- end
27
+ #{columns}
28
+ #{associations}
29
+ #{enum_instance_methods}
30
+ #{enum_scope_methods(singleton: true)}
31
+ #{scopes(singleton: true)}
32
+
33
+ #{relation_decl}
34
+
35
+ #{collection_proxy_decl}
36
+
37
+ #{footer}
31
38
  RBS
32
39
  end
33
40
 
34
41
  private def relation_decl
35
42
  <<~RBS
36
43
  class #{relation_class_name} < ActiveRecord::Relation
37
- include _ActiveRecord_Relation[#{klass.name}]
38
- include Enumerable[#{klass.name}]
39
- #{enum_scope_methods(singleton: false).indent(2)}
40
- #{scopes(singleton: false).indent(2)}
44
+ include _ActiveRecord_Relation[#{klass_name}]
45
+ include Enumerable[#{klass_name}]
46
+ #{enum_scope_methods(singleton: false)}
47
+ #{scopes(singleton: false)}
41
48
  end
42
49
  RBS
43
50
  end
44
51
 
45
52
  private def collection_proxy_decl
46
53
  <<~RBS
47
- class #{klass.name}::ActiveRecord_Associations_CollectionProxy < ActiveRecord::Associations::CollectionProxy
54
+ class ActiveRecord_Associations_CollectionProxy < ActiveRecord::Associations::CollectionProxy
48
55
  end
49
56
  RBS
50
57
  end
51
58
 
52
-
53
59
  private def header
54
- # @type var superclass: Class
55
- superclass = _ = klass.superclass
56
- "class #{klass.name} < #{superclass.name}"
60
+ namespace = +''
61
+ klass_name.split('::').map do |mod_name|
62
+ namespace += "::#{mod_name}"
63
+ mod_object = Object.const_get(namespace)
64
+ case mod_object
65
+ when Class
66
+ # @type var superclass: Class
67
+ superclass = _ = mod_object.superclass
68
+ superclass_name = Util.module_name(superclass)
69
+ @dependencies << superclass_name
70
+
71
+ "class #{mod_name} < #{superclass_name}"
72
+ when Module
73
+ "module #{mod_name}"
74
+ else
75
+ raise 'unreachable'
76
+ end
77
+ end.join("\n")
78
+ end
79
+
80
+ private def footer
81
+ "end\n" * klass_name.split('::').size
57
82
  end
58
83
 
59
84
  private def associations
@@ -67,7 +92,7 @@ module RbsRails
67
92
  private def has_many
68
93
  klass.reflect_on_all_associations(:has_many).map do |a|
69
94
  singular_name = a.name.to_s.singularize
70
- type = a.klass.name
95
+ type = Util.module_name(a.klass)
71
96
  collection_type = "#{type}::ActiveRecord_Associations_CollectionProxy"
72
97
  <<~RUBY.chomp
73
98
  def #{a.name}: () -> #{collection_type}
@@ -80,7 +105,7 @@ module RbsRails
80
105
 
81
106
  private def has_one
82
107
  klass.reflect_on_all_associations(:has_one).map do |a|
83
- type = a.polymorphic? ? 'untyped' : a.klass.name
108
+ type = a.polymorphic? ? 'untyped' : Util.module_name(a.klass)
84
109
  type_optional = optional(type)
85
110
  <<~RUBY.chomp
86
111
  def #{a.name}: () -> #{type}
@@ -95,7 +120,7 @@ module RbsRails
95
120
 
96
121
  private def belongs_to
97
122
  klass.reflect_on_all_associations(:belongs_to).map do |a|
98
- type = a.polymorphic? ? 'untyped' : a.klass.name
123
+ type = a.polymorphic? ? 'untyped' : Util.module_name(a.klass)
99
124
  type_optional = optional(type)
100
125
  <<~RUBY.chomp
101
126
  def #{a.name}: () -> #{type}
@@ -235,10 +260,7 @@ module RbsRails
235
260
  private def parse_model_file
236
261
  return @parse_model_file if defined?(@parse_model_file)
237
262
 
238
-
239
- # @type var class_name: String
240
- class_name = _ = klass.name
241
- path = Rails.root.join('app/models/', class_name.underscore + '.rb')
263
+ path = Rails.root.join('app/models/', klass_name.underscore + '.rb')
242
264
  return @parse_model_file = nil unless path.exist?
243
265
  return [] unless path.exist?
244
266
 
@@ -259,7 +281,7 @@ module RbsRails
259
281
  end
260
282
 
261
283
  private def relation_class_name
262
- "#{klass.name}::ActiveRecord_Relation"
284
+ "ActiveRecord_Relation"
263
285
  end
264
286
 
265
287
  private def columns
@@ -321,8 +343,7 @@ module RbsRails
321
343
  end
322
344
 
323
345
  private
324
- # @dynamic klass
325
- attr_reader :klass
346
+ attr_reader :klass, :klass_name
326
347
  end
327
348
  end
328
349
  end
@@ -0,0 +1,43 @@
1
+ module RbsRails
2
+ class DependencyBuilder
3
+ attr_reader :deps
4
+
5
+ def initialize
6
+ @deps = []
7
+ end
8
+
9
+ def build
10
+ dep_rbs = +""
11
+ done = Set.new(['ActiveRecord::Base', 'ActiveRecord', 'Object'])
12
+ deps.uniq!
13
+ while dep = deps.shift
14
+ next unless done.add?(dep)
15
+
16
+ case dep_object = Object.const_get(dep)
17
+ when Class
18
+ superclass = dep_object.superclass or raise
19
+ super_name = Util.module_name(superclass)
20
+ deps << super_name
21
+ dep_rbs << "class #{dep} < #{super_name} end\n"
22
+ when Module
23
+ dep_rbs << "module #{dep} end\n"
24
+ else
25
+ raise
26
+ end
27
+
28
+ # push namespaces
29
+ namespaces = dep.split('::')
30
+ namespaces.pop
31
+ namespaces.inject('') do |base, name|
32
+ full_name = base.empty? ? name : [base, name].join('::')
33
+ deps << full_name
34
+ full_name
35
+ end
36
+ end
37
+
38
+ unless dep_rbs.empty?
39
+ Util.format_rbs(dep_rbs)
40
+ end
41
+ end
42
+ end
43
+ end
@@ -3,7 +3,7 @@ require 'rake/tasklib'
3
3
 
4
4
  module RbsRails
5
5
  class RakeTask < Rake::TaskLib
6
- attr_accessor :ignore_model_if, :name
6
+ attr_accessor :ignore_model_if, :name, :signature_root_dir
7
7
 
8
8
  def initialize(name = :rbs_rails, &block)
9
9
  super()
@@ -12,6 +12,8 @@ module RbsRails
12
12
 
13
13
  block.call(self) if block
14
14
 
15
+ setup_signature_root_dir!
16
+
15
17
  def_copy_signature_files
16
18
  def_generate_rbs_for_models
17
19
  def_generate_rbs_for_path_helpers
@@ -30,9 +32,7 @@ module RbsRails
30
32
  task("#{name}:copy_signature_files": :environment) do
31
33
  require 'rbs_rails'
32
34
 
33
- to = Rails.root.join('sig/rbs_rails/')
34
- to.mkpath unless to.exist?
35
- RbsRails.copy_signatures(to: to)
35
+ RbsRails.copy_signatures(to: signature_root_dir)
36
36
  end
37
37
  end
38
38
 
@@ -41,23 +41,25 @@ module RbsRails
41
41
  task("#{name}:generate_rbs_for_models": :environment) do
42
42
  require 'rbs_rails'
43
43
 
44
- out_dir = Rails.root / 'sig'
45
- out_dir.mkdir unless out_dir.exist?
46
-
47
44
  Rails.application.eager_load!
48
45
 
46
+ dep_builder = DependencyBuilder.new
49
47
 
50
48
  # HACK: for steep
51
49
  (_ = ::ActiveRecord::Base).descendants.each do |klass|
52
50
  next if klass.abstract_class?
53
51
  next if ignore_model_if&.call(klass)
54
52
 
55
- path = out_dir / "app/models/#{klass.name.underscore}.rbs"
56
- FileUtils.mkdir_p(path.dirname)
53
+ path = signature_root_dir / "app/models/#{klass.name.underscore}.rbs"
54
+ path.dirname.mkpath
57
55
 
58
- sig = RbsRails::ActiveRecord.class_to_rbs(klass)
56
+ sig = RbsRails::ActiveRecord.class_to_rbs(klass, dependencies: dep_builder.deps)
59
57
  path.write sig
60
58
  end
59
+
60
+ if dep_rbs = dep_builder.build
61
+ signature_root_dir.join('model_dependencies.rbs').write(dep_rbs)
62
+ end
61
63
  end
62
64
  end
63
65
 
@@ -66,10 +68,16 @@ module RbsRails
66
68
  task("#{name}:generate_rbs_for_path_helpers": :environment) do
67
69
  require 'rbs_rails'
68
70
 
69
- out_path = Rails.root.join 'sig/path_helpers.rbs'
71
+ out_path = signature_root_dir.join 'path_helpers.rbs'
70
72
  rbs = RbsRails::PathHelpers.generate
71
73
  out_path.write rbs
72
74
  end
73
75
  end
76
+
77
+ private def setup_signature_root_dir!
78
+ @signature_root_dir ||= Rails.root / 'sig/rbs_rails'
79
+ @signature_root_dir = Pathname(@signature_root_dir)
80
+ @signature_root_dir.mkpath
81
+ end
74
82
  end
75
83
  end
@@ -0,0 +1,25 @@
1
+ module RbsRails
2
+ module Util
3
+ MODULE_NAME = Module.instance_method(:name)
4
+
5
+ extend self
6
+
7
+ if '2.7' <= RUBY_VERSION
8
+ def module_name(mod)
9
+ # HACK: RBS doesn't have UnboundMethod#bind_call
10
+ (_ = MODULE_NAME).bind_call(mod)
11
+ end
12
+ else
13
+ def module_name(mod)
14
+ MODULE_NAME.bind(mod).call
15
+ end
16
+ end
17
+
18
+ def format_rbs(rbs)
19
+ decls = RBS::Parser.parse_signature(rbs)
20
+ StringIO.new.tap do |io|
21
+ RBS::Writer.new(out: io).write(decls)
22
+ end.string
23
+ end
24
+ end
25
+ end
@@ -2,5 +2,5 @@ module RbsRails
2
2
  # Because of copy_signatures is defined by lib/rbs_rails.rb
3
3
  # @dynamic self.copy_signatures
4
4
 
5
- VERSION = "0.6.0"
5
+ VERSION = "0.7.0"
6
6
  end
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
19
19
  # Specify which files should be added to the gem when it is released.
20
20
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
21
21
  spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
22
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
22
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|gem_rbs)/}) }
23
23
  end
24
24
  spec.bindir = "exe"
25
25
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
@@ -1,11 +1,11 @@
1
1
  module RbsRails::ActiveRecord
2
- def self.class_to_rbs: (untyped klass) -> untyped
2
+ def self.class_to_rbs: (untyped klass, ?dependencies: Array[String]) -> untyped
3
3
  end
4
4
 
5
5
  class RbsRails::ActiveRecord::Generator
6
6
  @parse_model_file: nil | Parser::AST::Node
7
7
 
8
- def initialize: (singleton(ActiveRecord::Base) klass) -> untyped
8
+ def initialize: (singleton(ActiveRecord::Base) klass, dependencies: Array[String]) -> untyped
9
9
 
10
10
  def generate: () -> String
11
11
 
@@ -17,6 +17,8 @@ class RbsRails::ActiveRecord::Generator
17
17
 
18
18
  def header: () -> String
19
19
 
20
+ def footer: () -> String
21
+
20
22
  def associations: () -> String
21
23
 
22
24
  def has_many: () -> String
@@ -55,5 +57,9 @@ class RbsRails::ActiveRecord::Generator
55
57
 
56
58
  def optional: (String) -> String
57
59
 
60
+ private
61
+
58
62
  attr_reader klass: singleton(ActiveRecord::Base)
63
+
64
+ attr_reader klass_name: String
59
65
  end
@@ -0,0 +1,9 @@
1
+ module RbsRails
2
+ class DependencyBuilder
3
+ attr_reader deps: Array[String]
4
+
5
+ def initialize: () -> void
6
+
7
+ def build: () -> (String | nil)
8
+ end
9
+ end
@@ -7,6 +7,8 @@ module RbsRails
7
7
 
8
8
  attr_accessor name: Symbol
9
9
 
10
+ attr_accessor signature_root_dir: Pathname
11
+
10
12
  def initialize: (?::Symbol name) { (self) -> void } -> void
11
13
 
12
14
  def def_all: () -> void
@@ -16,5 +18,9 @@ module RbsRails
16
18
  def def_generate_rbs_for_models: () -> void
17
19
 
18
20
  def def_generate_rbs_for_path_helpers: () -> void
21
+
22
+ private
23
+
24
+ def setup_signature_root_dir!: () -> void
19
25
  end
20
26
  end
@@ -0,0 +1,11 @@
1
+ module RbsRails
2
+ module Util
3
+ MODULE_NAME: UnboundMethod
4
+
5
+ extend Util
6
+
7
+ def module_name: (Module) -> String
8
+
9
+ def format_rbs: (String) -> String
10
+ end
11
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rbs_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Masataka Pocke Kuwabara
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-12-24 00:00:00.000000000 Z
11
+ date: 2020-12-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parser
@@ -45,9 +45,10 @@ executables: []
45
45
  extensions: []
46
46
  extra_rdoc_files: []
47
47
  files:
48
+ - ".github/workflows/ci.yml"
48
49
  - ".gitignore"
49
50
  - ".gitmodules"
50
- - ".travis.yml"
51
+ - CHANGELOG.md
51
52
  - Gemfile
52
53
  - LICENSE
53
54
  - README.md
@@ -79,6 +80,7 @@ files:
79
80
  - assets/sig/tzinfo.rbs
80
81
  - bin/add-type-params.rb
81
82
  - bin/console
83
+ - bin/gem_rbs
82
84
  - bin/postprocess.rb
83
85
  - bin/rbs
84
86
  - bin/rbs-prototype-rb.rb
@@ -86,8 +88,10 @@ files:
86
88
  - bin/to-ascii.rb
87
89
  - lib/rbs_rails.rb
88
90
  - lib/rbs_rails/active_record.rb
91
+ - lib/rbs_rails/dependency_builder.rb
89
92
  - lib/rbs_rails/path_helpers.rb
90
93
  - lib/rbs_rails/rake_task.rb
94
+ - lib/rbs_rails/util.rb
91
95
  - lib/rbs_rails/version.rb
92
96
  - rbs_rails.gemspec
93
97
  - sig/fileutils.rbs
@@ -95,8 +99,10 @@ files:
95
99
  - sig/rake.rbs
96
100
  - sig/rbs_rails.rbs
97
101
  - sig/rbs_rails/active_record.rbs
102
+ - sig/rbs_rails/dependency_builder.rbs
98
103
  - sig/rbs_rails/path_helpers.rbs
99
104
  - sig/rbs_rails/rake_task.rbs
105
+ - sig/rbs_rails/util.rbs
100
106
  - sig/rbs_rails/version.rbs
101
107
  homepage: https://github.com/pocke/rbs_rails
102
108
  licenses:
@@ -119,7 +125,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
119
125
  - !ruby/object:Gem::Version
120
126
  version: '0'
121
127
  requirements: []
122
- rubygems_version: 3.2.3
128
+ rubygems_version: 3.1.4
123
129
  signing_key:
124
130
  specification_version: 4
125
131
  summary: A RBS files generator for Rails application
@@ -1,11 +0,0 @@
1
- language: ruby
2
-
3
- rvm:
4
- - 2.6.5
5
- - 2.7.0
6
- - ruby-head
7
-
8
- before_install:
9
- - gem install bundler -v 2.1.4
10
-
11
- cache: bundler