ncmb-ruby-client 0.0.6 → 0.0.8

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
  SHA1:
3
- metadata.gz: 448af6e36c731233c6857c9618ff96502f660721
4
- data.tar.gz: fd1363bd10de8213e43a67b82fe30803774e7d5b
3
+ metadata.gz: 12cc26d4c875deb46103f478e2d04bd752b813bc
4
+ data.tar.gz: 5b7cff028775e7e26dac5dde6093aa5a7c09ed1f
5
5
  SHA512:
6
- metadata.gz: 63b0f7174aca9b832151726243a9cbaf1d0e588afbebd39b5d2e43bbdf0d1983a26a29e4f66b1b5e8eccbadd601724f51bcab260ca1f01328587f3b203584e3b
7
- data.tar.gz: ed607647195dd9468ab348b3292019b570bd4158d7fa29eb972a7964d2dbb53c154fa54a2b1cb982c56c6b4e688a714dfeeb5a93e6c1694ccf52847c3db2734c
6
+ metadata.gz: f104345075bafde235ab95927daa6fbbf9a7c31901fb1a408a3a926f94ac44717024f19d4993440b293ff5bb21573629f7488150f641b5d170b38df04e9a5aab
7
+ data.tar.gz: 88edda35c363f9903be0591473571dcc285e1610a3dac6b4f856ab0c2c489756eb76ae48e4920d0119ddefef382d646a0f2a8c9165000b775b5d3f6ea8613c98
data/Gemfile CHANGED
@@ -2,4 +2,3 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in ncmb-ruby-client.gemspec
4
4
  gemspec
5
-
data/README.md CHANGED
@@ -10,8 +10,24 @@ Basic Usage
10
10
  NCMB.initialize application_key: application_key, client_key: client_key
11
11
 
12
12
  @todo = NCMB::DataStore.new 'Todo'
13
- @todo = @todo.limit(20).count(1).skip(0)
14
- puts "@todo[0].name #{@todo[0].name}"
13
+ @todo = @todo.limit(20)
14
+
15
+ @todo.each do |item|
16
+ puts item[:String]
17
+ puts " #{item[:Array]} -> #{item[:Array].class}"
18
+ end
19
+
20
+ @todo = NCMB::Object.new 'Todo'
21
+ @todo.set('String', 'Test String')
22
+ @todo.set('Integer', 100)
23
+ @todo.set('Boolean', true)
24
+ @todo.set('Array', [1, 2, 3, "Orange", "Tomato"])
25
+ @todo.set('Object', {test1: 'a', test2: 'b'})
26
+ @todo.set('Location', NCMB::GeoPoint.new(50, 30))
27
+ @todo.set('MultipleLine', "test\ntest\n")
28
+ @todo.set('Increment', NCMB::Increment.new(2))
29
+ @todo.set('Date', Time.new(2016, 2, 24, 12, 30, 45))
30
+ @todo.save
15
31
  ```
16
32
 
17
33
  ### Register push notification
@@ -5,9 +5,52 @@ require 'ncmb'
5
5
  require 'yaml'
6
6
  yaml = YAML.load_file(File.join(File.dirname(__FILE__), '..', 'setting.yml'))
7
7
  NCMB.initialize application_key: yaml['application_key'], client_key: yaml['client_key']
8
- @todo = NCMB::DataStore.new 'TestClass'
9
- @todo = @todo.limit(20).count(1).skip(0)
10
- # @todo = @todo.where(testKey: "testValue")
11
- # puts "@todo[0] #{@todo[0]}"
12
- puts "@todo[0].name #{@todo[0].message}"
8
+
9
+ example = NCMB::DataStore.new 'Example'
10
+ example.delete_all
11
+
12
+ 10.times do |i|
13
+ item = example.new
14
+ item.set('String', "テスト#{i}00")
15
+ item.set('Integer', i)
16
+ item.set('Boolean', true)
17
+ item.set('Array', [i, i * 2, i * 3, "Orange", "Tomato"])
18
+ item.set('Object', {test1: 'a', test2: 'b'})
19
+ item.set('Location', NCMB::GeoPoint.new((i + 1) * 10, (i + 2) * 5))
20
+ item.set('MultipleLine', "test\ntest\n")
21
+ item.set('Increment', NCMB::Increment.new(i + 1))
22
+ item.set('Date', Time.now)
23
+ item.save
24
+ sleep(2)
25
+ end
26
+
27
+ # @todo = @todo.limit(20).where("String", 'テスト100').greaterThan("Integer", 1)
28
+ # @todo = @todo.limit(20).notEqualTo("String", 'テスト100')
29
+ # @todo = @todo.limit(20).in("String", ['テスト100'])
30
+ # @todo = @todo.limit(20).notIn("String", ['テスト100'])
31
+ # @todo = @todo.limit(20).inArray("Array", [4])
32
+ # @todo = @todo.limit(20).notInArray("Array", ['Orange'])
33
+ # @todo = @todo.limit(20).allInArray("Array", [1, 2, 4])
34
+
35
+ geo1 = NCMB::GeoPoint.new(50, 30);
36
+ geo2 = NCMB::GeoPoint.new(51, 31);
37
+
38
+ # @todo = @todo.limit(20).withinKilometers("Location", geo1, 1000)
39
+ example = example.limit(1).withinSquare("Location", geo1, geo2)
40
+ begin
41
+ example.each_with_index do |item, i|
42
+ puts item[:String]
43
+ puts " #{item[:Array]} -> #{item[:Array].class}"
44
+ puts " #{item[:Location]} -> #{item[:Location].class}"
45
+ puts " #{item[:Date]} -> #{item[:Date].class}"
46
+ item.set('Increment', NCMB::Increment.new(i + 1))
47
+ item.update
48
+ # item.set('String', 'テスト200')
49
+ # item.update
50
+ end
51
+ rescue NCMB::FetchError => e
52
+ puts example.error
53
+ end
54
+
55
+ # puts "@todo[0].name #{@todo[0].text}"
13
56
 
data/lib/ncmb.rb CHANGED
@@ -1,6 +1,19 @@
1
1
  $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
2
  $:.unshift(File.dirname(__FILE__))
3
+
4
+ require 'time'
5
+ require 'openssl'
6
+ require 'base64'
7
+ require "net/http"
8
+ require "uri"
9
+ require "erb"
10
+ require "json"
11
+
3
12
  require "ncmb/version"
4
13
  require "ncmb/client"
5
14
  require "ncmb/data_store"
15
+ require "ncmb/object"
6
16
  require "ncmb/push"
17
+ require "ncmb/geo_point"
18
+ require "ncmb/increment"
19
+ require "ncmb/error"
data/lib/ncmb/client.rb CHANGED
@@ -1,9 +1,10 @@
1
- require 'time'
2
- require 'openssl'
3
- require 'base64'
4
- require "net/http"
5
- require "uri"
6
- require 'json'
1
+ class Time
2
+ def to_json(a)
3
+ v = self.getgm
4
+ "{\"__type\": \"Date\", \"iso\": \"#{v.iso8601(3)}\"}"
5
+ end
6
+ end
7
+
7
8
  module NCMB
8
9
  DOMAIN = 'mb.api.cloud.nifty.com'
9
10
  API_VERSION = '2013-09-01'
@@ -28,6 +29,14 @@ module NCMB
28
29
  def post(path, params)
29
30
  request :post, path, params
30
31
  end
32
+
33
+ def put(path, params)
34
+ request :put, path, params
35
+ end
36
+
37
+ def delete(path, params)
38
+ request :delete, path
39
+ end
31
40
 
32
41
  def array2hash(ary)
33
42
  new_v = {}
@@ -39,6 +48,7 @@ module NCMB
39
48
  new_v = [hash]
40
49
  end
41
50
  end
51
+ new_v = new_v.sort_by{|a, b| a.to_s}.to_h
42
52
  new_v
43
53
  end
44
54
 
@@ -46,28 +56,38 @@ module NCMB
46
56
  results = {}
47
57
  queries.each do |k, v|
48
58
  v = array2hash(v) if v.is_a? Array
49
- if v.is_a? Hash
50
- results[k.to_s] = URI.escape(v.to_json.to_s, /[^-_.!~*'()a-zA-Z\d;\/?@&=+$,#]/)
51
- else
52
- results[k.to_s] = URI.escape(v.to_s, /[^-_.!~*'()a-zA-Z\d;\/?@&=+$,#]/)
53
- end
59
+ value = URI.encode(v.is_a?(Hash) ? v.to_json : v.to_s).gsub("[", "%5B").gsub(":", "%3A").gsub("]", "%5D")
60
+ results[k.to_s] = value
54
61
  end
55
62
  results
56
63
  end
57
-
64
+
65
+ def change_query(queries = {})
66
+ results = {}
67
+ queries.each do |k, v|
68
+ case v
69
+ when NCMB::Increment
70
+ queries[k] = v.amount
71
+ end
72
+ end
73
+ queries
74
+ end
75
+
58
76
  def hash2query(queries = {})
59
77
  results = {}
60
78
  queries.each do |k, v|
61
- v = array2hash(v) if v.is_a? Array
62
- if v.is_a? Hash
63
- results[k.to_s] = v.to_json.to_s
79
+ # v = array2hash(v) if v.is_a? Array
80
+ puts "#{k} -> #{v.class}"
81
+ case v
82
+ when Hash, TrueClass, FalseClass, Array then
83
+ results[k.to_s] = v
84
+ when Time then
64
85
  else
65
86
  results[k.to_s] = v.to_s
66
87
  end
67
88
  end
68
- results.collect do |key, value|
69
- "#{key}=#{value}"
70
- end
89
+ puts results
90
+ results
71
91
  end
72
92
 
73
93
  def generate_signature(method, path, now = nil, queries = {})
@@ -91,7 +111,6 @@ module NCMB
91
111
  def request(method, path, queries = {})
92
112
  now = Time.now.utc.iso8601
93
113
  signature = generate_signature(method, path, now, queries)
94
- query = hash2query(queries).join("&")
95
114
  http = Net::HTTP.new(@domain, 443)
96
115
  http.use_ssl=true
97
116
  headers = {
@@ -100,11 +119,22 @@ module NCMB
100
119
  "X-NCMB-Timestamp" => now,
101
120
  "Content-Type" => 'application/json'
102
121
  }
103
- if method == :get
104
- path = path + URI.escape((query == '' ? "" : "?"+query), /[^-_.!~*'()a-zA-Z\d;\/?@&=+$,#]/)
122
+ # queries = hash2query(queries)
123
+ case method
124
+ when :get
125
+ query = encode_query(queries).map do |key, value|
126
+ "#{key}=#{value}"
127
+ end.join("&")
128
+ path = path + (query == '' ? "" : "?"+query)
105
129
  return JSON.parse(http.get(path, headers).body, symbolize_names: true)
106
- else
130
+ when :post
131
+ queries = change_query(queries)
107
132
  return JSON.parse(http.post(path, queries.to_json, headers).body, symbolize_names: true)
133
+ when :put
134
+ return JSON.parse(http.put(path, queries.to_json, headers).body, symbolize_names: true)
135
+ when :delete
136
+ http.delete(path, headers)
137
+ return {}
108
138
  end
109
139
  end
110
140
  end
@@ -3,106 +3,177 @@ module NCMB
3
3
  include NCMB
4
4
 
5
5
  def initialize(name, fields = {}, alc = "")
6
- @@name = name
7
- @@alc = alc
8
- @@fields = fields
9
- @@queries = {}
10
- @@items = nil
6
+ @name = name
7
+ @alc = alc
8
+ @fields = fields
9
+ @queries = {where: []}
10
+ @items = nil
11
11
  end
12
12
 
13
- def new *opt
14
- initialize opt
13
+ def error
14
+ @error
15
+ end
16
+
17
+ def new opt = {}
18
+ NCMB::Object.new @name, opt
15
19
  end
16
20
 
17
21
  def columns
18
- @@fields.keys
22
+ @fields.keys
19
23
  end
20
24
 
21
25
  def method_missing(name)
22
- if @@fields[name.to_sym]
23
- return @@fields[name.to_sym]
26
+ if @fields[name.to_sym]
27
+ return @fields[name.to_sym]
24
28
  else
25
- raise NoMethod, "#{name} is not found"
29
+ raise NoMethodError, "#{name} is not found"
26
30
  end
27
31
  end
28
32
 
29
- def call(name)
30
- @@fields[name.to_sym] || NoMethod
31
- end
32
-
33
33
  def each(&block)
34
- @@items.each(&block)
34
+ get.each(&block)
35
35
  end
36
36
 
37
37
  def each_with_index(&block)
38
- @@items.each_with_index(&block)
38
+ get.each_with_index(&block)
39
39
  end
40
40
 
41
41
  def order(field)
42
- @@queries[:order] = field
42
+ @queries[:order] = field
43
43
  self
44
44
  end
45
45
 
46
46
  def first
47
- return @@items.first unless @@items.nil?
48
- get(@@queries).first
47
+ get.first
49
48
  end
50
49
 
51
50
  def limit(count)
52
- @@queries[:limit] = count
51
+ @queries[:limit] = count
53
52
  self
54
53
  end
55
54
 
56
- def count(count)
57
- @@queries[:count] = count
55
+ def count
56
+ @queries[:count] = 1
58
57
  self
59
58
  end
60
59
 
61
60
  def skip(count)
62
- @@queries[:skip] = count
61
+ @queries[:skip] = count
63
62
  self
64
63
  end
65
64
 
66
- def where(params = {})
67
- @@queries[:where] = [] unless @@queries[:where]
68
- if params.size == 1
69
- @@queries[:where] << params
70
- else
71
- params.each do |hash|
72
- @@queries[:where] << hash
65
+ [
66
+ {greaterThan: "$gt"},
67
+ {notEqualTo: "$ne"},
68
+ {equalTo: nil},
69
+ {lessThan: "$lt"},
70
+ {lessThanOrEqualTo: "$lte"},
71
+ {greaterThanOrEqualTo: "$gte"},
72
+ {in: "$in"},
73
+ {notIn: "$nin"},
74
+ {exists: "$exists"},
75
+ {regex: "$regex"},
76
+ {inArray: "$inArray"},
77
+ {notInArray: "$ninArray"},
78
+ {allInArray: "$all"},
79
+ ].each do |m|
80
+ define_method m.keys.first do |name, value|
81
+ params = {}
82
+ if m.values.first.nil?
83
+ params[name] = value
84
+ else
85
+ params[name] = {}
86
+ params[name][m.values.first] = value
73
87
  end
88
+ @queries[:where] << params
89
+ self
74
90
  end
91
+ end
92
+
93
+ [
94
+ {withinKilometers: "$maxDistanceInKilometers"},
95
+ {withinMiles: "$maxDistanceInMiles"},
96
+ {withinRadians: "$maxDistanceInRadians"}
97
+ ].each do |m|
98
+ define_method m.keys.first do |name, geo, value|
99
+ params = {}
100
+ params[name] = {
101
+ "$nearSphere": geo,
102
+ }
103
+ params[name][m.values.first] = value
104
+ @queries[:where] << params
105
+ self
106
+ end
107
+ end
108
+
109
+ def withinSquare(name, geo1, geo2)
110
+ params = {}
111
+ params[name] = {
112
+ "$within": {
113
+ "$box": [
114
+ geo1,
115
+ geo2
116
+ ]
117
+ }
118
+ }
119
+ @queries[:where] << params
120
+ self
121
+ end
122
+
123
+ def where(name, value)
124
+ params = {}
125
+ params[name] = value
126
+ @queries[:where] << params
75
127
  self
76
128
  end
77
129
 
78
130
  def [](count)
79
- return @@items[count] unless @@items.nil?
80
- get(@@queries)[count]
131
+ get[count]
81
132
  end
82
133
 
83
- def get(queries = {})
84
- path = "/#{@@client.api_version}/classes/#{@@name}"
85
- results = @@client.get path, queries
134
+ def get
135
+ return @items unless @items.nil?
136
+ path = "/#{@@client.api_version}/classes/#{@name}"
137
+ results = @@client.get path, @queries
86
138
  return [] unless results
87
139
  if results[:error] && results[:error] != ""
88
- @@error = results
89
- raise 'error'
140
+ @error = results
141
+ raise NCMB::FetchError
142
+ end
143
+ if @queries[:count] == 1
144
+ return results[:count]
90
145
  end
91
- items = []
146
+ @items = []
92
147
  results[:results].each do |result|
148
+ result.each do |key, field|
149
+ if field.is_a?(Hash) && field[:__type] == 'GeoPoint'
150
+ result[key] = NCMB::GeoPoint.new(field[:latitude], field[:longitude])
151
+ end
152
+ if field.is_a?(Hash) && field[:__type] == 'Date'
153
+ result[key] = Time.parse(field[:iso])
154
+ end
155
+ end
93
156
  alc = result[:acl]
94
157
  result.delete(:acl)
95
- items << NCMB::DataStore.new(@@name, result, alc)
158
+ @items << NCMB::Object.new(@name, result, alc)
96
159
  end
97
- @@items = items
160
+ @items
98
161
  end
99
162
 
100
- def post(queries = {})
101
- path = "/#{@@client.api_version}/classes/#{@@name}"
102
- result = @@client.post path, queries
103
- alc = result[:acl]
104
- result.delete(:acl)
105
- NCMB::DataStore.new(@@name, result, alc)
163
+ def delete_all
164
+ max = 1000
165
+ count = self.limit(max).count().get
166
+ if count == 0
167
+ return true
168
+ end
169
+ @queries.delete :count
170
+ self.limit(max).each do |item|
171
+ item.delete
172
+ end
173
+ if count > max
174
+ return delete_all
175
+ end
176
+ true
106
177
  end
107
178
  end
108
179
  end
data/lib/ncmb/error.rb ADDED
@@ -0,0 +1,4 @@
1
+ module NCMB
2
+ class FetchError < StandardError
3
+ end
4
+ end
@@ -0,0 +1,18 @@
1
+ module NCMB
2
+ class GeoPoint
3
+ include NCMB
4
+
5
+ def initialize(latitude, longitude)
6
+ @latitude = latitude
7
+ @longitude = longitude
8
+ end
9
+
10
+ def to_json(a = "")
11
+ "{\"__type\": \"GeoPoint\", \"longitude\": #{@longitude}, \"latitude\": #{@latitude}}"
12
+ end
13
+
14
+ def to_s
15
+ "GeoPoint (latitude: #{@latitude}, longitude: #{@longitude})"
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,17 @@
1
+ module NCMB
2
+ class Increment
3
+ include NCMB
4
+
5
+ def initialize(amount = 1)
6
+ @amount = amount
7
+ end
8
+
9
+ def to_json(a)
10
+ "{\"__op\": \"Increment\", \"amount\": #{@amount}}"
11
+ end
12
+
13
+ def amount
14
+ @amount
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,57 @@
1
+ module NCMB
2
+ class Object
3
+ include NCMB
4
+
5
+ def initialize(name, fields = {}, alc = "")
6
+ @name = name
7
+ @alc = alc
8
+ @fields = fields
9
+ end
10
+
11
+ def method_missing(name)
12
+ sym = name.to_sym
13
+ if @fields.has_key?(sym)
14
+ return @fields[sym]
15
+ else
16
+ raise NoMethodError, "#{name} is not found"
17
+ end
18
+ end
19
+
20
+ def set(name, value)
21
+ @fields[name] = value
22
+ end
23
+
24
+ def call(name)
25
+ @fields[name.to_sym] || NoMethodError
26
+ end
27
+
28
+ def [](key)
29
+ @fields[key]
30
+ end
31
+
32
+ def post
33
+ path = "/#{@@client.api_version}/classes/#{@name}"
34
+ result = @@client.post path, @fields
35
+ alc = result[:acl]
36
+ result.delete(:acl)
37
+ NCMB::Object.new(@name, result, alc)
38
+ end
39
+ alias :save :post
40
+
41
+ def put
42
+ path = "/#{@@client.api_version}/classes/#{@name}/#{@fields[:objectId]}"
43
+ params = @fields
44
+ params.delete :objectId
45
+ params.delete :createDate
46
+ params.delete :updateDate
47
+ result = @@client.put path, params
48
+ @fields[:updateDate] = result[:updateDate]
49
+ end
50
+ alias :update :put
51
+
52
+ def delete
53
+ path = "/#{@@client.api_version}/classes/#{@name}/#{@fields[:objectId]}"
54
+ @@client.delete path, {}
55
+ end
56
+ end
57
+ end
data/lib/ncmb/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Ncmb
2
- VERSION = "0.0.6"
2
+ VERSION = "0.0.8"
3
3
  end
@@ -0,0 +1,20 @@
1
+ require "spec_helper"
2
+ describe NCMB do
3
+ before do
4
+ yaml = YAML.load_file(File.join(File.dirname(__FILE__), '..', 'setting.yml'))
5
+ @ncmb = NCMB::Client.new(application_key: yaml['application_key'],
6
+ client_key: yaml['client_key']
7
+ )
8
+ @object_id = @ncmb.post('/2013-09-01/classes/TODO', todo: "Test task")[:objectId]
9
+ end
10
+
11
+ it "Delete #1" do
12
+ res = @ncmb.delete("/2013-09-01/classes/TODO/#{@object_id}")
13
+ res.should == {}
14
+ end
15
+
16
+ it "Delete #2" do
17
+ res = @ncmb.delete("/2013-09-01/classes/TODO/doesnotexist")
18
+ res[:code].should == 'E404001'
19
+ end
20
+ end
data/spec/put_spec.rb ADDED
@@ -0,0 +1,15 @@
1
+ require "spec_helper"
2
+ describe NCMB do
3
+ before do
4
+ yaml = YAML.load_file(File.join(File.dirname(__FILE__), '..', 'setting.yml'))
5
+ @ncmb = NCMB::Client.new(application_key: yaml['application_key'],
6
+ client_key: yaml['client_key']
7
+ )
8
+ @object_id = @ncmb.post('/2013-09-01/classes/TODO', todo: "Test task")[:objectId]
9
+ end
10
+
11
+ it "Put #1" do
12
+ res = @ncmb.put("/2013-09-01/classes/TODO/#{@object_id}", todo: "Test task updated")
13
+ res[:updateDate].should_not be_nil
14
+ end
15
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ncmb-ruby-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Atsushi Nakatsugawa
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-18 00:00:00.000000000 Z
11
+ date: 2016-09-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -74,12 +74,18 @@ files:
74
74
  - lib/ncmb/client.rb
75
75
  - lib/ncmb/data_store.rb
76
76
  - lib/ncmb/device.rb
77
+ - lib/ncmb/error.rb
78
+ - lib/ncmb/geo_point.rb
79
+ - lib/ncmb/increment.rb
80
+ - lib/ncmb/object.rb
77
81
  - lib/ncmb/push.rb
78
82
  - lib/ncmb/version.rb
79
83
  - ncmb-ruby-client.gemspec
80
84
  - setting_default.yml
85
+ - spec/delete_spec.rb
81
86
  - spec/get_spec.rb
82
87
  - spec/post_spec.rb
88
+ - spec/put_spec.rb
83
89
  - spec/spec_helper.rb
84
90
  homepage: http://mb.cloud.nifty.com/
85
91
  licenses:
@@ -101,11 +107,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
101
107
  version: '0'
102
108
  requirements: []
103
109
  rubyforge_project:
104
- rubygems_version: 2.2.2
110
+ rubygems_version: 2.5.1
105
111
  signing_key:
106
112
  specification_version: 4
107
113
  summary: A simple Ruby client for the nifty cloud mobile backend REST API
108
114
  test_files:
115
+ - spec/delete_spec.rb
109
116
  - spec/get_spec.rb
110
117
  - spec/post_spec.rb
118
+ - spec/put_spec.rb
111
119
  - spec/spec_helper.rb