ShyCouch 0.3.5 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +1 -1
- data/README +18 -4
- data/Rakefile +2 -1
- data/ShyCouch.gemspec +4 -3
- data/VERSION +1 -1
- data/lib/ShyCouch.rb +29 -41
- data/lib/ShyCouch/data.rb +66 -24
- data/test/test_ShyCouch.rb +5 -2
- data/test/test_couch_document.rb +5 -5
- data/test/test_views.rb +51 -0
- metadata +18 -17
data/Gemfile.lock
CHANGED
data/README
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
= ShyCouch
|
2
2
|
|
3
|
-
ShyCouch is a Ruby library for CouchDB. It's a data persistence layer that uses native objects and
|
3
|
+
ShyCouch is a Ruby library for CouchDB. It's a data persistence layer that uses native objects and lets you write native Ruby blocks that'll be parsed into MapReduce JavaScript functions.
|
4
4
|
|
5
|
-
|
5
|
+
The structure is a bit of a mess, but essentially it provides:
|
6
6
|
|
7
|
-
|
7
|
+
- a database object
|
8
|
+
- a CouchDocument object, which is a glorified hash
|
9
|
+
- a Design object representing the Design document for an app in CouchDB
|
8
10
|
|
9
|
-
|
11
|
+
At the moment, all views have to be written manually. I'm currently evaluating the wisdom of building a query language to dynamically write views and cache them in Couch.
|
10
12
|
|
11
13
|
= Usage
|
12
14
|
|
15
|
+
require 'shycouch'
|
16
|
+
settings = {
|
17
|
+
"db"=> {
|
18
|
+
"host" => "ramponeau.local",
|
19
|
+
"port" => 5984,
|
20
|
+
"name" => "food",
|
21
|
+
"user" => "cerales",
|
22
|
+
"password" => "password"
|
23
|
+
},
|
24
|
+
}
|
25
|
+
db = ShyCouch::CouchDatabase()
|
26
|
+
|
13
27
|
== Models
|
14
28
|
|
15
29
|
You don't need to define entity relationships or anything. Your models can just look like this:
|
data/Rakefile
CHANGED
data/ShyCouch.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{ShyCouch}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.4.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = [%q{Shy Inc.}, %q{Daniel Bryan}, %q{Cerales}]
|
12
|
-
s.date = %q{2011-08-
|
12
|
+
s.date = %q{2011-08-28}
|
13
13
|
s.description = %q{Ruby API for CouchDB, designed to work with the Camping micro-framework.}
|
14
14
|
s.email = %q{danbryan@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -37,7 +37,8 @@ Gem::Specification.new do |s|
|
|
37
37
|
"test/test_couchdb_api.rb",
|
38
38
|
"test/test_couchdb_factory.rb",
|
39
39
|
"test/test_design_documents.rb",
|
40
|
-
"test/test_fields.rb"
|
40
|
+
"test/test_fields.rb",
|
41
|
+
"test/test_views.rb"
|
41
42
|
]
|
42
43
|
s.homepage = %q{http://github.com/Cerales/ShyCouch}
|
43
44
|
s.licenses = [%q{MIT}]
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.4.0
|
data/lib/ShyCouch.rb
CHANGED
@@ -11,63 +11,37 @@ $:.unshift(File.dirname(__FILE__)) unless
|
|
11
11
|
require 'net/http'
|
12
12
|
require 'json'
|
13
13
|
require 'resolv'
|
14
|
-
require 'shyrubyjs'
|
14
|
+
# require 'shyrubyjs'
|
15
|
+
require '~/dev/gems/ShyRubyJS/lib/ShyRubyJS'
|
15
16
|
# require everything from the 'ShyCouch' subdirectory
|
16
17
|
Dir.new(File.dirname(__FILE__)+'/ShyCouch').each { |f| require 'shycouch/' + f.split('.')[0] unless f == '.' or f == '..' }
|
17
18
|
|
18
19
|
|
19
20
|
module ShyCouch
|
20
21
|
class << self
|
21
|
-
def goes(m)
|
22
|
-
Camping.goes m
|
23
|
-
c = %{
|
24
|
-
#{m.to_s}::Models::CouchDocument = ShyCouch::Data::CouchDocument
|
25
|
-
}
|
26
|
-
eval(c)
|
27
|
-
ShyCouch.create
|
28
|
-
end
|
29
22
|
|
30
|
-
def create(settings=nil)
|
23
|
+
def create(settings=nil) #TODO - change this
|
31
24
|
$couchdb = ShyCouch.getDB(settings)
|
32
25
|
end
|
33
26
|
|
34
27
|
def getDB(settings=nil)
|
35
|
-
settings = $
|
36
|
-
database =
|
37
|
-
puts database.connect unless database.connect["ok"]
|
28
|
+
settings = $couch_settings unless settings
|
29
|
+
database = CouchDatabase.new(settings)
|
30
|
+
puts database.connect unless database.connect["ok"] #TODO - hm
|
38
31
|
database.create unless database.on_server?
|
39
32
|
return database
|
40
33
|
end
|
41
34
|
|
42
35
|
end
|
43
36
|
attr_accessor :database
|
44
|
-
|
45
|
-
class Connection
|
46
|
-
# Test that the database is accessible and give back a CouchDBAPI object if so.
|
47
|
-
# Doesn't actually gets instantiated - is just here to allow nice ShyCouch::Connection.Create syntax
|
48
|
-
# def self.Create(settings=nil)
|
49
|
-
# settings = $settings unless settings
|
50
|
-
# database = CouchDBAPI.new(settings["db"]["host"], settings["db"]["port"], settings["db"]["name"], settings["db"]["user"], settings["db"]["password"])
|
51
|
-
# puts database.connect unless database.connect["ok"]
|
52
|
-
# database.create unless database.on_server?
|
53
|
-
# return database
|
54
|
-
# end
|
55
|
-
|
56
|
-
def push_generic_views
|
57
|
-
#TODO
|
58
|
-
end
|
59
|
-
end
|
60
37
|
|
61
|
-
class
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
38
|
+
class ShyCouchError < StandardError; end
|
39
|
+
|
40
|
+
class CouchDatabase
|
41
|
+
def initialize(settings)
|
42
|
+
# args = explode_settings(args) if args.size == 1
|
43
|
+
init(settings)
|
66
44
|
end
|
67
|
-
#
|
68
|
-
# def initialize(*settings)
|
69
|
-
# @host, @port, @name, @user, @password = settings["db"]["host"], settings["db"]["port"], settings["db"]["name"], settings["db"]["user"], settings["db"]["password"]
|
70
|
-
# end
|
71
45
|
|
72
46
|
attr_accessor :server, :name, :host, :port, :views
|
73
47
|
|
@@ -134,6 +108,14 @@ module ShyCouch
|
|
134
108
|
end
|
135
109
|
|
136
110
|
private
|
111
|
+
|
112
|
+
def init(settings)
|
113
|
+
db_settings = settings["db"]
|
114
|
+
@host, @port, @name, @user, @password = db_settings["host"],db_settings["port"], db_settings["name"],db_settings["user"], db_settings["password"]
|
115
|
+
@views = []
|
116
|
+
@server = CouchServerConnection.allocate
|
117
|
+
end
|
118
|
+
|
137
119
|
class CouchServerConnection
|
138
120
|
def initialize(args, options=nil)#host, port, user, password, options = nil)
|
139
121
|
@host = args["host"]
|
@@ -237,9 +219,13 @@ module ShyCouch
|
|
237
219
|
|
238
220
|
private
|
239
221
|
|
240
|
-
def
|
222
|
+
def handle_failure(req, res)
|
241
223
|
raise RuntimeError.new("#{res.code}:#{res.message}\nMETHOD:#{req.method}\nURI:#{req.path}\n#{res.body}")
|
242
224
|
end
|
225
|
+
|
226
|
+
def handle_error(e)
|
227
|
+
raise RuntimeError.new("#{e.inspect}\n Maybe be due to illegal rev or id change")
|
228
|
+
end
|
243
229
|
|
244
230
|
def request(req)
|
245
231
|
res = Net::HTTP.start(@host, @port) { |http|
|
@@ -247,11 +233,13 @@ module ShyCouch
|
|
247
233
|
http.request(req)
|
248
234
|
}
|
249
235
|
unless res.kind_of?(Net::HTTPSuccess)
|
250
|
-
|
236
|
+
handle_failure(req, res)
|
251
237
|
end
|
252
238
|
res
|
239
|
+
rescue Errno::ECONNRESET => e
|
240
|
+
handle_error(e)
|
253
241
|
end
|
254
242
|
end
|
255
|
-
|
243
|
+
|
256
244
|
end
|
257
245
|
end
|
data/lib/ShyCouch/data.rb
CHANGED
@@ -5,9 +5,9 @@ module ShyCouch
|
|
5
5
|
class CouchDocument < Hash
|
6
6
|
class << self
|
7
7
|
# allows instance.class.requirements to be called
|
8
|
-
attr_accessor :requirements
|
9
8
|
end
|
10
|
-
|
9
|
+
@@needs, @@suggests = [], []
|
10
|
+
|
11
11
|
def initialize(hash={})
|
12
12
|
# Assumes that the "kind" is the class name unless explicitly stated otherwise
|
13
13
|
# TODO - maybe just force it to be the class name no matter what tbh
|
@@ -17,27 +17,30 @@ module ShyCouch
|
|
17
17
|
# super(hash)
|
18
18
|
end
|
19
19
|
|
20
|
-
# def initialize(hash=nil, requirements)
|
21
|
-
# @requirements = requirements
|
22
|
-
# merge!(hash) if hash
|
23
|
-
# raise TypeError unless valid? #TODO - should raise a more specific and useful error
|
24
|
-
# end
|
25
|
-
|
26
20
|
def self.all
|
27
|
-
database = CouchDatabase.new($settings)
|
28
|
-
database.get()
|
29
21
|
end
|
30
|
-
|
31
|
-
def self.
|
32
|
-
|
22
|
+
|
23
|
+
def self.needs(*requirements)
|
24
|
+
requirements.map { |requirement| @@needs << requirement } unless requirements.empty?
|
25
|
+
return @@needs
|
33
26
|
end
|
34
|
-
|
35
|
-
def
|
36
|
-
|
37
|
-
|
38
|
-
self[key] = value
|
27
|
+
|
28
|
+
def self.suggests(*suggestions)
|
29
|
+
suggestions.map { |suggestion| @@suggests << suggestion } unless suggestions.empty?
|
30
|
+
return @@suggests
|
39
31
|
end
|
40
|
-
|
32
|
+
|
33
|
+
def needs;self.class.needs; end
|
34
|
+
def suggests; self.class.suggests; end
|
35
|
+
|
36
|
+
def needs?(requirement)
|
37
|
+
@@needs.include?(requirement) ? true : false
|
38
|
+
end
|
39
|
+
|
40
|
+
def suggests?(requirement)
|
41
|
+
@@suggests.include?(requirement) ? true : false
|
42
|
+
end
|
43
|
+
|
41
44
|
def attr_keys
|
42
45
|
# returns the keys for all the attrs that aren't the id or rev
|
43
46
|
attr_keys = []
|
@@ -90,15 +93,54 @@ module ShyCouch
|
|
90
93
|
end
|
91
94
|
|
92
95
|
end
|
96
|
+
|
97
|
+
class View
|
98
|
+
attr_accessor :map, :reduce, :name
|
99
|
+
|
100
|
+
def initialize(view_name, &block)
|
101
|
+
@parser = ShyRubyJS::ShySexpParser.new
|
102
|
+
sexp_check = block.to_sexp
|
103
|
+
sexp = block.to_sexp(:strip_enclosure=>true)
|
104
|
+
|
105
|
+
# make sure the two blocks inside are calls to "map" and "reduce"
|
106
|
+
|
107
|
+
@name = view_name.to_s
|
108
|
+
if sexp[0] == :block
|
109
|
+
unless sexp_check[3][1][1][2] == :map and sexp_check[3][2][1][2] == :reduce
|
110
|
+
raise ShyCouchError, "view must be called with map block and optional reduce block"
|
111
|
+
end
|
112
|
+
[1,2].each { |num|
|
113
|
+
2.times { sexp[num].delete_at(1) }
|
114
|
+
}
|
115
|
+
@map = @parser.parse(sexp[1])[0]
|
116
|
+
@reduce = @parser.parse(sexp[2]) if sexp[2].length > 1
|
117
|
+
elsif sexp[0] == :iter
|
118
|
+
raise ShyCouchError, "view must be called with map block and optional reduce block" unless sexp[1][2] == :map
|
119
|
+
@map = @parser.parse(sexp[3])
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def as_hash
|
124
|
+
h = {}
|
125
|
+
h[@name] = {"map" => @map}
|
126
|
+
h.merge!({"reduce" => @reduce}) if @reduce
|
127
|
+
return h
|
128
|
+
end
|
129
|
+
end
|
93
130
|
|
94
131
|
class Design < CouchDocument
|
95
132
|
# this is used to manage design documents
|
96
133
|
# In practise, the Controllers should be a list of classes corresponding to design documents
|
97
|
-
|
98
|
-
def
|
99
|
-
|
100
|
-
|
101
|
-
|
134
|
+
|
135
|
+
def initialize(name)
|
136
|
+
merge! "_id" => "_design/#{name.to_s}"
|
137
|
+
@parser = ShyRubyJS::ShySexpParser.new
|
138
|
+
end
|
139
|
+
|
140
|
+
def self.setup
|
141
|
+
# setup_all_view
|
142
|
+
end
|
143
|
+
|
102
144
|
def push;end #must override push in order to set the ID
|
103
145
|
end
|
104
146
|
|
data/test/test_ShyCouch.rb
CHANGED
@@ -7,7 +7,8 @@ require_relative '../lib/ShyCouch'
|
|
7
7
|
# Settings for a database that is set up and working, with an admin user
|
8
8
|
$settings = {
|
9
9
|
"db"=> {
|
10
|
-
"host" => "
|
10
|
+
"host" => "ramponeau.local",
|
11
|
+
# "host" => "localhost",
|
11
12
|
"port" => 5984,
|
12
13
|
"name" => "test",
|
13
14
|
"user" => "cerales",
|
@@ -29,4 +30,6 @@ require_relative 'test_camping_integration'
|
|
29
30
|
|
30
31
|
require_relative 'test_couchdb_factory'
|
31
32
|
|
32
|
-
require_relative 'test_design_documents'
|
33
|
+
require_relative 'test_design_documents'
|
34
|
+
|
35
|
+
require_relative 'test_views'
|
data/test/test_couch_document.rb
CHANGED
@@ -38,7 +38,7 @@ class CouchDocumentTests# < Test::Unit::TestCase
|
|
38
38
|
def test_create_from_fixnum
|
39
39
|
# Ensure no doc creation with fixnum argument
|
40
40
|
fixnum = 1
|
41
|
-
|
41
|
+
assert_raise TypeError do
|
42
42
|
doc = ShyCouch::Data::CouchDocument.new(fixnum)
|
43
43
|
end
|
44
44
|
end
|
@@ -110,9 +110,9 @@ class CouchDocumentTests# < Test::Unit::TestCase
|
|
110
110
|
@existing_valid_documents.each { |doc|
|
111
111
|
# add some more attributes
|
112
112
|
assert(doc._rev)
|
113
|
-
doc
|
114
|
-
doc
|
115
|
-
doc
|
113
|
+
doc["owner"] = "the guvvmint"
|
114
|
+
doc["buttonCount"] = nil
|
115
|
+
doc["friends"] = nil
|
116
116
|
doc.buttonCount = 5
|
117
117
|
doc.friends = ["alan", "alex", "all me other mates"]
|
118
118
|
|
@@ -132,7 +132,7 @@ class CouchDocumentTests# < Test::Unit::TestCase
|
|
132
132
|
def test_illegal_change_to_rev
|
133
133
|
@existing_valid_documents.each { |doc|
|
134
134
|
doc._rev = "hurr"
|
135
|
-
|
135
|
+
assert_raise RuntimeError do
|
136
136
|
res = doc.push
|
137
137
|
end
|
138
138
|
}
|
data/test/test_views.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require_relative '../lib/ShyCouch.rb'
|
3
|
+
|
4
|
+
class CouchViewTests < Test::Unit::TestCase
|
5
|
+
JS_MAP_FUNCTION_HEADER = "function ( doc ) { \n "
|
6
|
+
JS_REDUCE_FUNCTION_HEADER = "function(key, values, rereduce)"
|
7
|
+
JS_FUNCTION_FOOTER = "}"
|
8
|
+
def setup
|
9
|
+
@couch_views = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def view(view_name, &block)
|
13
|
+
@couch_views << ShyCouch::Data::View.new(view_name, &block)
|
14
|
+
end
|
15
|
+
def teardown; end
|
16
|
+
|
17
|
+
def test_define_map_view
|
18
|
+
view :five_star_butts do
|
19
|
+
map do
|
20
|
+
def function(doc)
|
21
|
+
emit(doc) if doc.kind == "butt" and doc.star_rating == 5
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
expected_js = JS_MAP_FUNCTION_HEADER + %{if( doc.kind == "butt" && doc.star_rating == 5 ) {\n emit(doc)\n} \n } + JS_FUNCTION_FOOTER
|
26
|
+
assert_equal(expected_js, @couch_views[0].map)
|
27
|
+
# puts @couch_views[0].map
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_define_map_and_reduce_view
|
31
|
+
view :beggar_count do
|
32
|
+
map do
|
33
|
+
def function(doc)
|
34
|
+
emit(doc) if doc.kind == "beggar"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
reduce do
|
38
|
+
def function(key, values, rereduce)
|
39
|
+
return sum(values)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
puts @couch_views[0].map
|
44
|
+
puts @couch_views[0].reduce
|
45
|
+
expected_map = JS_MAP_FUNCTION_HEADER + %{if( doc.kind == "beggar" ) {\n emit(doc)\n} \n } + JS_FUNCTION_FOOTER
|
46
|
+
expected_rejuce = JS_REDUCE_FUNCTION_HEADER
|
47
|
+
assert_equal(expected_map, @couch_views[0].map)
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ShyCouch
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,11 +11,11 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2011-08-
|
14
|
+
date: 2011-08-28 00:00:00.000000000Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: bundler
|
18
|
-
requirement: &
|
18
|
+
requirement: &70288155812040 !ruby/object:Gem::Requirement
|
19
19
|
none: false
|
20
20
|
requirements:
|
21
21
|
- - ~>
|
@@ -23,10 +23,10 @@ dependencies:
|
|
23
23
|
version: 1.0.0
|
24
24
|
type: :development
|
25
25
|
prerelease: false
|
26
|
-
version_requirements: *
|
26
|
+
version_requirements: *70288155812040
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: jeweler
|
29
|
-
requirement: &
|
29
|
+
requirement: &70288155810560 !ruby/object:Gem::Requirement
|
30
30
|
none: false
|
31
31
|
requirements:
|
32
32
|
- - ~>
|
@@ -34,10 +34,10 @@ dependencies:
|
|
34
34
|
version: 1.6.4
|
35
35
|
type: :development
|
36
36
|
prerelease: false
|
37
|
-
version_requirements: *
|
37
|
+
version_requirements: *70288155810560
|
38
38
|
- !ruby/object:Gem::Dependency
|
39
39
|
name: rcov
|
40
|
-
requirement: &
|
40
|
+
requirement: &70288155807920 !ruby/object:Gem::Requirement
|
41
41
|
none: false
|
42
42
|
requirements:
|
43
43
|
- - ! '>='
|
@@ -45,10 +45,10 @@ dependencies:
|
|
45
45
|
version: '0'
|
46
46
|
type: :development
|
47
47
|
prerelease: false
|
48
|
-
version_requirements: *
|
48
|
+
version_requirements: *70288155807920
|
49
49
|
- !ruby/object:Gem::Dependency
|
50
50
|
name: sourcify
|
51
|
-
requirement: &
|
51
|
+
requirement: &70288155806340 !ruby/object:Gem::Requirement
|
52
52
|
none: false
|
53
53
|
requirements:
|
54
54
|
- - ~>
|
@@ -56,10 +56,10 @@ dependencies:
|
|
56
56
|
version: 0.5.0
|
57
57
|
type: :development
|
58
58
|
prerelease: false
|
59
|
-
version_requirements: *
|
59
|
+
version_requirements: *70288155806340
|
60
60
|
- !ruby/object:Gem::Dependency
|
61
61
|
name: ShyRubyJS
|
62
|
-
requirement: &
|
62
|
+
requirement: &70288155792060 !ruby/object:Gem::Requirement
|
63
63
|
none: false
|
64
64
|
requirements:
|
65
65
|
- - ! '>='
|
@@ -67,10 +67,10 @@ dependencies:
|
|
67
67
|
version: '0'
|
68
68
|
type: :development
|
69
69
|
prerelease: false
|
70
|
-
version_requirements: *
|
70
|
+
version_requirements: *70288155792060
|
71
71
|
- !ruby/object:Gem::Dependency
|
72
72
|
name: ShyRubyJS
|
73
|
-
requirement: &
|
73
|
+
requirement: &70288155790660 !ruby/object:Gem::Requirement
|
74
74
|
none: false
|
75
75
|
requirements:
|
76
76
|
- - ! '>='
|
@@ -78,10 +78,10 @@ dependencies:
|
|
78
78
|
version: '0'
|
79
79
|
type: :runtime
|
80
80
|
prerelease: false
|
81
|
-
version_requirements: *
|
81
|
+
version_requirements: *70288155790660
|
82
82
|
- !ruby/object:Gem::Dependency
|
83
83
|
name: sourcify
|
84
|
-
requirement: &
|
84
|
+
requirement: &70288155789540 !ruby/object:Gem::Requirement
|
85
85
|
none: false
|
86
86
|
requirements:
|
87
87
|
- - ! '>='
|
@@ -89,7 +89,7 @@ dependencies:
|
|
89
89
|
version: '0'
|
90
90
|
type: :runtime
|
91
91
|
prerelease: false
|
92
|
-
version_requirements: *
|
92
|
+
version_requirements: *70288155789540
|
93
93
|
description: Ruby API for CouchDB, designed to work with the Camping micro-framework.
|
94
94
|
email: danbryan@gmail.com
|
95
95
|
executables: []
|
@@ -119,6 +119,7 @@ files:
|
|
119
119
|
- test/test_couchdb_factory.rb
|
120
120
|
- test/test_design_documents.rb
|
121
121
|
- test/test_fields.rb
|
122
|
+
- test/test_views.rb
|
122
123
|
homepage: http://github.com/Cerales/ShyCouch
|
123
124
|
licenses:
|
124
125
|
- MIT
|
@@ -134,7 +135,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
134
135
|
version: '0'
|
135
136
|
segments:
|
136
137
|
- 0
|
137
|
-
hash:
|
138
|
+
hash: 1563418179645536452
|
138
139
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
139
140
|
none: false
|
140
141
|
requirements:
|