opium 1.3.5 → 1.4.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
  SHA1:
3
- metadata.gz: ba3e984219298d9044d897b69174d070e97203ea
4
- data.tar.gz: a75539396c4cf16ce7663a6cb2aa0014cf7a5284
3
+ metadata.gz: f2703590e11e240c7ad03f62e04a0c19ff0cdf11
4
+ data.tar.gz: 139dac0e475494014a9996e417d2332705aba373
5
5
  SHA512:
6
- metadata.gz: 01cb3c6a85d9b7164453c422ce2c760a0f30fe16d5130275acc95499e9684c7d7aaeedb39df18241752609c150fd2a5a8bed52f1e5bdb476d06f0ff96d2f3269
7
- data.tar.gz: 0592a85febebccaae06eb14d3688d3cb33809d6ba185ff481b76b54c6c9b57f26726f53509e16ac4a763420a60390e9bf5716671a90519873c31849056fb43c4
6
+ metadata.gz: 81e4d0868f9e80dc8d08412bcf4b54ca67007d39bfb17c10a77ae9997fa4f7822775f9c6bc3e0ba5ae951c9bb22291fadca78529adb4602c8d9c8620ac0a7f10
7
+ data.tar.gz: 340904910c91a3a50f7a1d38420cddca627653aca189507af4240fdb524ae545f98e5427e6c17c4c203b22898023a5a774c61a5d30a565525e72f6a8dde7ed85
data/.travis.yml CHANGED
@@ -2,10 +2,10 @@ language: ruby
2
2
  cache: bundler
3
3
 
4
4
  rvm:
5
- - 1.9.3
6
5
  - 2.0.0
7
6
  - 2.1.2
8
7
  - 2.2.0
8
+ - 2.3.1
9
9
 
10
10
  before_install:
11
11
  - gem update bundler
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 1.4.0
2
+ ### New Features
3
+ - #52: Opium should now be capable of easily connecting to a custom parse-server instance hosted on a third party server.
4
+
1
5
  ## 1.3.5
2
6
  ### New Features
3
7
  - Due to ignorance, missed a method override for Opium::GeoPoint ===. Now implemented at the class level as well as at the instance level.
data/README.md CHANGED
@@ -37,7 +37,18 @@ $ rails g opium:config
37
37
 
38
38
  See the generated file at `config/opium.yml` for more details
39
39
 
40
- #### Model Generator
40
+ ### Parse.com server closure note
41
+
42
+ Opium was originally written to communicate with apps hosted on Parse.com; as hosted parse is hitting end-of-life in January 2017, any parse apps which wish to continue using the infrastructure need to be [migrated to third-party hosted parse-server instance](https://www.parse.com/migration).
43
+
44
+ As of version 1.4.0, Opium should be able to communicate with these third-party installations. Within the generated configuration file, two settings need to be updated to point Opium at the proper server instance:
45
+
46
+ - `server_url`: the URL of the server on which a parser-server API instance is hosted.
47
+ - `mount_point`: the sub-URI endpoint on `server_url` where Opium can reach the API.
48
+
49
+ As the config file suggests, it is suggested that these values be provided in a server environment via environment variables.
50
+
51
+ ### Model Generator
41
52
 
42
53
  A generator exists for creating new models; this should be invoked whenever `rails g model` gets invoked.
43
54
 
@@ -45,6 +56,12 @@ A generator exists for creating new models; this should be invoked whenever `rai
45
56
  $ rails g model game title:string price:float
46
57
  ```
47
58
 
59
+ A separate generate is available for creating a model to wrap Parse's User model:
60
+
61
+ ```bash
62
+ $ rails g opium:user
63
+ ```
64
+
48
65
  ### Specifying a model
49
66
 
50
67
  Models are defined by mixing in `Opium::Model` into a new class. Class names should match the names of the
@@ -54,7 +71,7 @@ class.
54
71
  ```ruby
55
72
  class Game
56
73
  include Opium::Model
57
-
74
+
58
75
  field :title, type: String
59
76
  field :price, type: Float
60
77
  end
@@ -63,6 +80,324 @@ end
63
80
  All models automatically come with three fields: *:id*, *:created_at*, and *:updated_at*. Field names are
64
81
  converted from a native ruby snake_case naming convention to a Parse lowerCamel convention.
65
82
 
83
+ #### Field data types
84
+
85
+ Opium comes with support for a variety of different data types for fields. These automatically will convert native ruby representations of the stored values to values supported by the parse backend, and conversely. At this time, Opium supports the following field types, where the first column is the type specified in ruby, and the second column is the type as stored in parse.
86
+
87
+ | Ruby Type | Parse Type |
88
+ |-----------------|------------|
89
+ | Integer | Number |
90
+ | Float | Number |
91
+ | String | String |
92
+ | Symbol | String |
93
+ | Date | Date |
94
+ | DateTime | Date |
95
+ | Time | Date |
96
+ | Array | Array |
97
+ | Opium::Boolean | Boolean |
98
+ | Opium::GeoPoint | GeoPoint |
99
+ | Opium::File | File |
100
+ | Opium::Pointer | Pointer |
101
+
102
+ Field setters will generally attempt to convert any incoming value to a native ruby representation, as noted above. Opium will automatically convert these values to a parse-friendly representation as necessary: e.g., when performing a query or persisting data.
103
+
104
+ Setting the type for a field is done by specifying the `:type` option on the field method. If this option is not present, the field will default to a ruby type of `Object`, which acts as a pass-through of the values coming from and going to parse. In the example from the last section, the `Game` model has two fields, one which is specified as having a `String` type, while the other has a `Float` type.
105
+
106
+ #### Field options
107
+
108
+ Fields can be modified by a small set of options passed to their definition:
109
+
110
+ - `readonly`: Expects a boolean value. If present, Opium will prevent the field from being altered locally. (The associated parse column may still be modified from other locations outside of Opium.)
111
+ - `as`: Expects a string or symbol value. If present, this will specify the name of the associated column within parse where the value should be stored. This allows the field to be named something more semantically useful locally.
112
+ - `type`: See the previous section. Expects a class constant.
113
+ - `default`: Expects either a logically convertible literal or a lambda providing the same. If a lambda is provided, it will be evaluated each time a model is instantiated, unless a value is provided for the field.
114
+
115
+ ```ruby
116
+ class Article
117
+ include Opium::Model
118
+
119
+ field :title, type: String, readonly: true
120
+ field :edited_on, type: Date, as: :last_edited
121
+ field :published_at, type: Date, default: -> { Time.now }
122
+ end
123
+ ```
124
+
125
+ In the preceding example, an `Article` is never allowed to alter its `title`, while its `last_edited` field is locally aliased as `edited_on`, and it will provide a default value for `published_at`, should none otherwise be provided.
126
+
127
+ #### Model associations
128
+
129
+ Opium currently supports basic associations between models: an owning model can specify that it `has_many` of another model, which can specify that it `belongs_to` the former.
130
+
131
+ ```ruby
132
+ class Player
133
+ # ...
134
+ has_many :high_scores
135
+ # ...
136
+ end
137
+
138
+ class HighScore
139
+ # ...
140
+ belongs_to :player
141
+ # ...
142
+ end
143
+ ```
144
+
145
+ Opium will attempt to infer the class name and inverse method of an association by standard Rails naming conventions: the singular, classified variant of the method name is taken to be the target class. In case naming conventions prohibit this inference from working properly, the following options are available:
146
+
147
+ - `class_name`: Expects a string. In case the class name cannot be inferred from the association name, it can be provided by this option.
148
+ - `inverse_of`: Expects a string or a symbol. In case the inverse method name cannot be inferred from the association name or its class name, it can be provided by this option.
149
+
150
+ Associations will be covered in more detail in the sections covering [creating models](#creating-and-updating-models) and [querying data](#querying-data). For now, note that Opium will attempt to manage the relationships between associated models for you and provides a robust, Rails-centric approach to manipulating and querying them.
151
+
152
+ #### Model field metadata
153
+
154
+ A set of utility class methods are provided to survey the defined fields and associations on any given model:
155
+
156
+ - `#fields`: returns a hash of all defined fields, keyed by the name of the field. Each value stored within the hash is an [`Opium::Model::Field`](lib/opium/model/field.rb) object, which has methods which reflect the settings discussed in [Field options](#field-options).
157
+ - `#has_field?` / `#field?`: expects a string or symbol, and returns a boolean value denoting whether the field is currently defined on the model.
158
+ - `#relations`: returns a hash of all defined associations, keyed by the method name used to define the relationship on the current model. Each value is a [`Opium::Model::Relatable::Metadata`](lib/opium/model/relatable/metadata.rb), which contains details pertaining to what the association is being made between.
159
+
160
+ Each of these methods would be called on the model you wish to inspect. In the following example, we ask the `Player` model if it has a `:name` field, get all of its readonly fields, and grab a list of its associations:
161
+
162
+ ```ruby
163
+ class Player
164
+ include Opium::Model
165
+ field :name, type: String
166
+ field :gamer_score, type: Integer
167
+ has_many :high_scores
168
+ has_many :played_games, class_name: 'GameSave', inverse_of: :played_by
169
+ end
170
+
171
+ # Should output the message, as Player does define a field called "name"
172
+ puts "'Player' has a name field!" if Player.has_field? :name
173
+
174
+ # Winnows the collection of field definitions by selecting only those which are readonly.
175
+ readonly_fields = Player.fields.select {|_, field| field.readonly?}
176
+
177
+ # #relations is a hash, indexed by name; in this example, the output should include the text "high_scores, played_games".
178
+ puts "'Player' defines the following associations: #{ Player.relations.keys.join(', ') }"
179
+ ```
180
+
181
+ Model metadata is readonly; it shouldn't be updated after the model has been defined. It might be useful, however, for writing model concerns or some sort of view decorator to help DRY up model usage in Rails.
182
+
183
+ #### Validations
184
+
185
+ Opium provides access to `ActiveModel::Validations` on a per model basis, so it is possible to validate the integrity of any data stored within an instance prior to saving it. Validations follow the normal ActiveModel format:
186
+
187
+ ```ruby
188
+ class Article
189
+ include Opium::Model
190
+ field :title, type: String
191
+ # ...
192
+ validates :title, presence: true
193
+ end
194
+
195
+ article = Article.new
196
+ article.valid? # false, as .title is nil.
197
+ article.errors # Standard ActiveModel::Errors object
198
+ article.title = 'Wibbly Wobbly Timey Wimey'
199
+ article.valid? # true, as .title has a value.
200
+ ```
201
+
202
+ As is standard with `ActiveModel` compliant libraries, attempting to save an invalid model will either return false (and not trigger the save) or raise an exception, depending upon how the save was triggered.
203
+
204
+ #### Callback hooks
205
+
206
+ Each Opium model has a set of callback points which can be hooked into. Adhering to the standard of `ActiveModel::Callbacks`, these provide a model a means by which to tie into various parts of an instance's lifecycle.
207
+
208
+ A full list of the available callbacks can be found by accessing the following constant:
209
+
210
+ ```ruby
211
+ Opium::Model::Callbacks::CALLBACKS
212
+ ```
213
+
214
+ Opium defines callbacks for the following events:
215
+
216
+ | Event / Action | Supported hooks |
217
+ |----------------|-----------------------|
218
+ | Save | before, after, around |
219
+ | Create | before, after, around |
220
+ | Update | before, after, around |
221
+ | Destroy | before, after, around |
222
+ | Initialize | after |
223
+ | Find | after |
224
+ | Touch | after |
225
+ | Validation | before, after |
226
+
227
+ To define a callback, do something like in the following example. (This example uses Dirty attributes, which are discussed in the next section.)
228
+
229
+ ```ruby
230
+ class Game
231
+ # ...
232
+ field :price, type: Float
233
+ has_many :on_wishlists, class_name: Wishlist
234
+ # ...
235
+
236
+ before_save :notify_price_drop
237
+
238
+ private
239
+
240
+ def notify_price_drop
241
+ if price_changed? && price_was > price
242
+ # Send a message to all players who have the game on their wishlist ...
243
+ end
244
+ end
245
+ end
246
+ ```
247
+
248
+ Please note that callbacks are only invokable within the context of Opium running in Ruby itself; these do not define Cloud Code JavaScript methods within the parse-server backend. If you need to tie into an instance's lifecycle outside the scope of a Ruby project, it is suggested that you look at using Cloud Code directly.
249
+
250
+ #### Dirty attribute tracking
251
+
252
+ Models will automatically gain attribute tracking, provided by `ActiveModel::Dirty`. As the fields of a model are altered, specialty events, of the form `<field-name>_will_change!` will be raised. At any point prior to saving, you can use the full suite of Dirty methods to query an instance about changes which have occurred to it. Dirty tracking follows a cycle: upon instance initialization, the model has no changes; upon a field changing, the current set of changes is updated; upon successfully saving the model, the current changes are cleared, and the previous changes get updated.
253
+
254
+ ```ruby
255
+ class Article
256
+ include Opium::Model
257
+ field :title, type: String
258
+ field :body, type: String
259
+ end
260
+
261
+ article = Article.new
262
+ article.changes # Should be empty
263
+
264
+ # As we are updating the .title, it'll flag the dirty tracking with its update;
265
+ # as it has changed, some output denoting the alteration should be made.
266
+ article.title = 'Something happen'
267
+ puts article.title_change.inspect if article.title_changed?
268
+ ```
269
+
270
+ Dirty tracking is provided for any attribute defined by the [`field`](#specifying-a-model) method.
271
+
272
+ #### JSON serialization
273
+
274
+ All Opium models should be serializable to JSON, using `ActiveModel::Serialization`. Note that a model instance does not include a root node.
275
+
276
+ JSON serialization is built around an object's `attributes` hash, which is publicly accessible. By default, all fields of the model are included within this hash. You can also store non-field data within `attributes` and have it show up in the JSON output.
277
+
278
+ Be aware that all Opium models use `ActiveModel::ForbiddenAttributesProtection` for mass assignment sanitization.
279
+
280
+ ### Creating and updating models
281
+
282
+ After defining a model with Opium, you might want to create new instances of it, or update the data of an existing instance. Opium has been designed to be familiar to anyone who has used other Rails-centric ORMs, such as ActiveRecord. In this regard, object creation follows two patterns: delayed persistence, and immediate persistence.
283
+
284
+ With delayed persistence, a model object is partially built and capable of being manipulated before being persisted. To finally create the model in parse-server, call its `save` method:
285
+
286
+ ```ruby
287
+ class Player
288
+ include Opium::Model
289
+ field :name, type: String
290
+ field :gamer_score, type: Integer, default: 0
291
+ end
292
+
293
+ player = Player.new( name: 'The Doctor' )
294
+ player.gamer_score = 1000
295
+
296
+ player.persisted? # false, as it has not yet been saved
297
+ player.new_record? # true, as it has not yet been saved
298
+
299
+ if player.save
300
+ # persisted!
301
+ player.persisted? # true, as it has been saved
302
+ else
303
+ # there was a problem!
304
+ end
305
+ ```
306
+
307
+ As this example suggests, you build a new model instance by calling its constructor, which accepts an attributes hash. The model may be altered and updated to taste. When ready to save, call the `save` method. `save` will run validations on the model, fire off any defined callbacks, update dirty tracking, and attempt to persist the model to parse-server. Should any of these steps fail, `save` will return false, and halt the operation at the point of failure. Otherwise, `save` will return true.
308
+
309
+ Alternatively, you can use `save!`, which, in the event of a failure, will raise an exception.
310
+
311
+ Note that the model's `id`, `created_at`, and `updated_at` fields will not have a value until it has been persisted.
312
+
313
+ With immediate persistence, a model object is built and then immediately stored to parse-server. This is achieved using the `create` class method, which accepts an attributes hash:
314
+
315
+ ```ruby
316
+ player = Player.create( name: 'The Doctor', gamer_score: 1000 )
317
+ player.persisted? # true, as it has been saved
318
+ ```
319
+
320
+ `create` behaves like `save!`: if there was a failure at any point in the persistence process, an exception will be raised. If there is no failure, the object returned by the method is a persisted model within parse-server.
321
+
322
+ Updating a model follows a similar set of patterns: at any time you wish to store changes to a persisted model, call `save` or `save!`:
323
+
324
+ ```ruby
325
+ player.gamer_score += 50
326
+ player.save!
327
+ ```
328
+
329
+ Alternatively, if you want to update the attributes of a model and save it simultaneously, you can do so with either `update` or `update!`, which behave analogously to the save methods:
330
+
331
+ ```ruby
332
+ if player.update( gamer_score: player.gamer_score + 50 )
333
+ # persisted!
334
+ else
335
+ # There was a problem!
336
+ end
337
+
338
+ player.update!( gamer_score: 2000 )
339
+ ```
340
+
341
+ `update` is aliased as `update_attributes`, and `update!` is aliased as `update_attributes!`; use whichever makes more semantic sense to you.
342
+
343
+ If a model has any associations, it will attempt to persist the changes to the association, which might very well cause a cascade of persistence. Opium will attempt to only trigger a save call to a model if it needs to. Due to parse-server's unique way of representing model associations in its API, updating the association between two models does require a separate API call. Be wary when attempting to modify many models simultaneously.
344
+
345
+ When you define an association between two models, one of those models receives a special collection field of type `Opium::Model::Relation` for storing instances of the other model. This collection has utility methods for building new instances of the associated model:
346
+
347
+ ```ruby
348
+ class Player
349
+ # ...
350
+ has_many :high_scores
351
+ # ...
352
+ end
353
+
354
+ class HighScore
355
+ # ...
356
+ belongs_to :player
357
+ # ...
358
+ end
359
+
360
+ player = Player.new
361
+ player.high_scores.class # Opium::Model::Relation
362
+ player.high_scores.count # 0, as there are none, yet.
363
+
364
+ score1 = player.high_scores.build
365
+ score1.value = 200
366
+
367
+ # .build is aliased as .new; either accepts an attributes hash.
368
+ score2 = player.high_scores.new( value: 1000 )
369
+
370
+ player.high_scores.count # 2, from the previous actions
371
+
372
+ fail "That shouldn't have happened" unless score1.player == player
373
+ ```
374
+
375
+ As you might expect, using a relation's build method will automatically add the built associated model to the collection; using this method will also cause the built model to point at the owner of the collection. You can also update the owner of a particular model on that model directly:
376
+
377
+ ```ruby
378
+ score3 = HighScore.new( value: 10000 )
379
+ score3.player = player
380
+
381
+ player.high_scores.include?( score3 ) # true, as the above setter updates player.
382
+ ```
383
+
384
+ ### Querying data
385
+
386
+ #### Find by id
387
+
388
+ #### Criteria & Scopes
389
+
390
+ #### Kaminari support
391
+
392
+ Opium comes with support for [Kaminari](https://rubygems.org/gems/kaminari). To ensure that Opium loads itself correctly, please specify it _after_ Kaminari within your Gemfile:
393
+
394
+ ```Gemfile
395
+ gem 'kaminari'
396
+ gem 'opium'
397
+ ```
398
+
399
+ Models and Criteria will gain the methods defined by Kaminari, and should be compatible with Kaminari's pagination partials.
400
+
66
401
  ## Contributing
67
402
 
68
403
  1. Fork it ( https://github.com/[my-github-username]/opium/fork )
@@ -1,25 +1,37 @@
1
1
  development:
2
2
  # The Application ID for your Parse app. Mandatory
3
3
  app_id: PARSE-APP-ID
4
-
4
+
5
5
  # The REST API key for your Parse app. Mandatory
6
6
  api_key: PARSE-API-KEY
7
-
8
- # Your Parse app's master key setting. You may omit this,
9
- # but you will be unable to edit Users except by ACL rules
7
+
8
+ # Your Parse app's master key setting. You may omit this,
9
+ # but you will be unable to edit Users except by ACL rules.
10
10
  master_key: PARSE-MASTER-KEY
11
-
11
+
12
12
  # You can store your app's webhook key here; Opium currently does not use this.
13
13
  webhook_key: PARSE-WEBHOOK-KEY
14
-
14
+
15
+ # The URL of the server where the parse API is available. For hosted parse, this
16
+ # should be https://api.parse.com; for a parse-server installation, this will be
17
+ # whatever server the instance is running on.
18
+ server_url: https://api.parse.com
19
+
20
+ # The sub-URI on :server_url where the parse-server API is available. For hosted
21
+ # parse, this should be /1; for a default parse-server-example installation, this
22
+ # defaults to /parse.
23
+ mount_point: /1
24
+
15
25
  # Any communications done with parse will either be (true) displayed or (false) silenced
16
26
  log_network_responses: false
17
-
27
+
18
28
  test:
19
29
  app_id: PARSE-TEST-APP-ID
20
30
  api_key: PARSE-TEST-API-KEY
21
31
  master_key: PARSE-TEST-MASTER-KEY
22
32
  webhook_key: PARSE-TEST-WEBHOOK-KEY
33
+ server_url: https://api.parse.com
34
+ mount_point: /1
23
35
  log_network_responses: true
24
36
 
25
37
  # You could hardcode the values for the production Parse app here, but it is suggested
@@ -29,4 +41,6 @@ production:
29
41
  api_key: <%= ENV['PARSE_API_KEY'] %>
30
42
  master_key: <%= ENV['PARSE_MASTER_KEY'] %>
31
43
  webhook_key: <%= ENV['PARSE_WEBHOOK_KEY'] %>
32
- log_network_responses: false
44
+ server_url: <%= ENV['PARSE_SERVER_URL'] %>
45
+ mount_point: <%= ENV['PARSE_MOUNT_POINT'] %>
46
+ log_network_responses: false
data/lib/opium/config.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module Opium
2
2
  extend self
3
-
3
+
4
4
  def configure
5
5
  yield config
6
6
  end
@@ -8,7 +8,7 @@ module Opium
8
8
  def config
9
9
  @config ||= Opium::Config.new
10
10
  end
11
-
11
+
12
12
  def load!( path, environment = nil )
13
13
  settings = load_yaml( path, environment )
14
14
  configure do |config|
@@ -17,11 +17,11 @@ module Opium
17
17
  end
18
18
  end
19
19
  end
20
-
20
+
21
21
  def reset
22
22
  @config = nil
23
23
  end
24
-
24
+
25
25
  private
26
26
 
27
27
  def load_yaml( path, environment = nil )
@@ -32,14 +32,16 @@ module Opium
32
32
  def env_name
33
33
  defined?( Rails ) ? Rails.env : ( ENV["RACK_ENV"] || ENV["OPIUM_ENV"] || raise( "Could not determine environment" ) )
34
34
  end
35
-
35
+
36
36
  class Config
37
37
  include ActiveSupport::Configurable
38
-
38
+
39
39
  config_accessor( :app_id ) { 'PARSE_APP_ID' }
40
40
  config_accessor( :api_key ) { 'PARSE_API_KEY' }
41
41
  config_accessor( :master_key ) { 'PARSE_MASTER_KEY' }
42
42
  config_accessor( :webhook_key ) { 'PARSE_WEBHOOK_KEY' }
43
43
  config_accessor( :log_network_responses ) { false }
44
+ config_accessor( :server_url ) { 'https://api.parse.com' }
45
+ config_accessor( :mount_point ) { '/1' }
44
46
  end
45
- end
47
+ end
@@ -19,8 +19,12 @@ module Opium
19
19
  end
20
20
 
21
21
  module ClassMethods
22
+ def parse_server_url
23
+ ::URI.join( ::Opium.config.server_url, ::Opium.config.mount_point ).to_s
24
+ end
25
+
22
26
  def connection
23
- @@connection ||= Faraday.new( url: 'https://api.parse.com/1/' ) do |faraday|
27
+ @@connection ||= Faraday.new( url: parse_server_url ) do |faraday|
24
28
  faraday.request :multipart
25
29
  faraday.request :url_encoded
26
30
  faraday.request :json
data/lib/opium/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Opium
2
- VERSION = "1.3.5"
2
+ VERSION = "1.4.0"
3
3
  end
data/opium.gemspec CHANGED
@@ -6,7 +6,7 @@ require 'opium/version'
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "opium"
8
8
  spec.version = Opium::VERSION
9
- spec.required_ruby_version = '>= 1.9.3'
9
+ spec.required_ruby_version = '>= 2.0.0'
10
10
  spec.authors = ["Joshua Bowers"]
11
11
  spec.email = ["joshua.bowers+code@gmail.com"]
12
12
  spec.summary = %q{An Object Parse.com Mapping technology for defining models.}
@@ -3,4 +3,6 @@ test:
3
3
  api_key: efgh5678
4
4
  master_key: 9012ijkl
5
5
  webhook_key: mnop7654
6
- log_network_responses: true
6
+ log_network_responses: true
7
+ server_url: https://example.com
8
+ mount_point: /parse
@@ -1,60 +1,68 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Opium do
4
- it { should respond_to(:configure, :config) }
5
- it { should respond_to(:load!).with(2).arguments }
6
- it { should respond_to(:reset) }
7
-
8
- describe ':configure' do
4
+ it { is_expected.to respond_to( :configure, :config ) }
5
+ it { is_expected.to respond_to( :load! ).with(2).arguments }
6
+ it { is_expected.to respond_to( :reset ) }
7
+
8
+ describe '.configure' do
9
9
  it do
10
10
  expect {|b| Opium.configure(&b) }.to yield_with_args
11
11
  end
12
12
  end
13
-
14
- describe ':config' do
13
+
14
+ describe '.config' do
15
15
  subject { Opium.config }
16
-
17
- it { should_not be_nil }
18
- it { should be_an( Opium::Config ) }
16
+
17
+ it { is_expected.to_not be_nil }
18
+ it { is_expected.to be_an( Opium::Config ) }
19
19
  end
20
-
21
- describe ':reset' do
20
+
21
+ describe '.reset' do
22
22
  after { described_class.config.log_network_responses = false }
23
-
23
+
24
24
  it 'should put all changed settings back to their defaults' do
25
25
  expect { described_class.config.log_network_responses = true }.to change( described_class.config, :log_network_responses ).from( false ).to( true )
26
26
  described_class.reset
27
27
  described_class.config.log_network_responses.should == false
28
28
  end
29
29
  end
30
-
31
- describe ':load!' do
30
+
31
+ describe '.load!' do
32
32
  let(:file) { File.join( File.dirname( __FILE__ ), 'config', 'opium.yml' ) }
33
-
33
+
34
34
  before do
35
35
  described_class.load!( file, :test )
36
36
  end
37
-
37
+
38
38
  after do
39
39
  described_class.reset
40
40
  end
41
-
42
- it { subject.config.app_id.should == 'abcd1234' }
43
- it { subject.config.api_key.should == 'efgh5678' }
44
- it { subject.config.master_key.should == '9012ijkl' }
45
- it { subject.config.webhook_key.should == 'mnop7654' }
46
- it { subject.config.log_network_responses.should == true }
41
+
42
+ subject(:config) { described_class.config }
43
+
44
+ context 'a valid config file' do
45
+ it { expect( config.app_id ).to eq 'abcd1234' }
46
+ it { expect( config.api_key ).to eq 'efgh5678' }
47
+ it { expect( config.master_key ).to eq '9012ijkl' }
48
+ it { expect( config.webhook_key ).to eq 'mnop7654' }
49
+ it { expect( config.log_network_responses ).to eq true }
50
+ it { expect( config.server_url ).to eq 'https://example.com' }
51
+ it { expect( config.mount_point ).to eq '/parse' }
52
+ end
47
53
  end
48
-
54
+
49
55
  describe Opium::Config do
50
- it { is_expected.to respond_to( :app_id, :api_key, :master_key, :webhook_key, :log_network_responses ) }
51
-
52
- describe 'defaults' do
53
- its(:app_id) { should == 'PARSE_APP_ID' }
54
- its(:api_key) { should == 'PARSE_API_KEY' }
55
- its(:master_key) { should == 'PARSE_MASTER_KEY' }
56
- its(:webhook_key) { should == 'PARSE_WEBHOOK_KEY' }
57
- its(:log_network_responses) { should == false }
56
+ it { is_expected.to respond_to( :app_id, :api_key, :master_key, :webhook_key, :log_network_responses, :server_url, :mount_point ) }
57
+
58
+ context 'a default config' do
59
+ it { expect( subject.app_id ).to eq 'PARSE_APP_ID' }
60
+ it { expect( subject.api_key ).to eq 'PARSE_API_KEY' }
61
+ it { expect( subject.master_key ).to eq 'PARSE_MASTER_KEY' }
62
+ it { expect( subject.webhook_key ).to eq 'PARSE_WEBHOOK_KEY' }
63
+ it { expect( subject.log_network_responses ).to eq false }
64
+ it { expect( subject.server_url ).to eq 'https://api.parse.com' }
65
+ it { expect( subject.mount_point ).to eq '/1' }
58
66
  end
59
67
  end
60
- end
68
+ end