gamifier 1.0.8 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/README.md CHANGED
@@ -22,6 +22,12 @@ Or install it yourself as:
22
22
  Configure Gamifier with the right parameter for the API you're using:
23
23
 
24
24
  Gamifier.set :key => "1234", :uri => "http://sandbox.v2.badgeville.com/api/berlin/"
25
+
26
+ Gamifier support the last version of Badgeville API using *enterprise api key*:
27
+
28
+ Gamifier.set :key => '1234', :uri => "http://sandbox.v2.badgeville.com/api/berlin/", :enterprise_key => '5678'
29
+
30
+ *Note that you have to specify either a private API key or an enterprise API key.*
25
31
 
26
32
  Then here is an example usage to credit an existing player:
27
33
 
@@ -35,16 +41,58 @@ declare activities, rewards and missions, and you can execute a DSL as
35
41
  follows:
36
42
 
37
43
  BADGEVILLE_KEY=xzy bundle exec ruby -I lib examples/dev.rb
44
+
45
+ ## Create Network using the DSL
46
+
47
+ Since the new Badgeville API, you can create new Network and API Keys using the Badgeville API. We updated the DSL for you:
48
+
49
+ network = Gamifier.dsl do
50
+ set :label, 'MyNetwork'
51
+ set :email, 'dev@mynetwork.com'
52
+
53
+ api_key do
54
+ set :access, 'public'
55
+ end
56
+
57
+ api_key do
58
+ set :access, 'private'
59
+ end
60
+
61
+ site 'foo' do
62
+ # as usual here
63
+ end
64
+ end
65
+
66
+ To only save the network on Badgeville do:
67
+
68
+ network.save_network!
69
+
70
+ To only save the sites, behaviors, rewards, etc do:
71
+
72
+ network.save!
73
+
74
+ If you want to create a new Network and create Sites, Behaviors, Rewards, etc on that new Network, you'll need the network's private API key.
75
+
76
+ api_key do
77
+ set :access, 'private'
78
+ end
79
+
80
+ These lines will create a new Private API key on current network. You'll need to:
81
+
82
+ 1. Create and Save the network: `network.save_network!`
83
+ 2. Create and Save the sites, behaviors and so on: `network.save!`
84
+
85
+ `network.save!` will use by default the new private API key if any, otherwise it will fallback to Gamifier's config.
38
86
 
39
87
  ## Tests
40
88
 
41
89
  Run the unit tests with:
42
90
 
43
- bundle exec spec spec/unit
91
+ bundle exec rspec spec/unit
44
92
 
45
93
  Run the integration tests as follows:
46
94
 
47
- BADGEVILLE_KEY=1234 bundle exec spec spec/integration
95
+ BADGEVILLE_KEY=1234 bundle exec rspec spec/integration
48
96
 
49
97
  ## Contributing
50
98
 
@@ -52,9 +100,13 @@ Run the integration tests as follows:
52
100
  2. Create your feature branch (`git checkout -b my-new-feature`)
53
101
  3. Commit your changes (`git commit -am 'Added some feature'`)
54
102
  4. Push to the branch (`git push origin my-new-feature`)
55
- 5. Create new Pull Request
103
+ 5. Create new Pull Request on Github
56
104
 
57
105
 
58
106
  ## Authors
59
107
 
60
108
  * Cyril Rohr <cyril.rohr@gmail.com>
109
+
110
+ ## Contributors
111
+
112
+ * [Pierre-Louis Gottfrois](https://github.com/gottfrois)
data/examples/dev.rb CHANGED
@@ -1,10 +1,21 @@
1
1
  require 'gamifier'
2
2
  require 'json'
3
3
 
4
- Gamifier.set :uri => "http://sandbox.v2.badgeville.com/api/berlin/", :key => ENV.fetch('BADGEVILLE_KEY')
4
+ Gamifier.set :uri => "http://sandbox.v2.badgeville.com/api/berlin/", :key => ENV.fetch('BADGEVILLE_KEY'), :enterprise_key => ENV.fetch('BADGEVILLE_ENTERPRISE_KEY')
5
5
  Gamifier.logger.level = Logger::DEBUG
6
6
 
7
7
  network = Gamifier.dsl do
8
+ set :label, 'MyNetwork'
9
+ set :email, 'dev@mynetwork.com'
10
+
11
+ api_key do
12
+ set :access, 'public'
13
+ end
14
+
15
+ api_key do
16
+ set :access, 'private'
17
+ end
18
+
8
19
  site 'dev.domain-test.crohr.me' do |site|
9
20
  set :url, 'dev.domain-test.crohr.me'
10
21
 
@@ -69,15 +80,15 @@ network = Gamifier.dsl do
69
80
  # set :adjustment, {
70
81
  # :points => 1, :karma => 1
71
82
  # }
72
- #
83
+ #
73
84
  # set :enable_count_limiting, true
74
85
  # set :limit_per_player, 10
75
86
  # set :limit_field_scope, 'category_id'
76
- #
87
+ #
77
88
  # set :enable_rate_limiting, true
78
89
  # set :bucket_max_capacity, 2
79
90
  # set :bucket_drain_rate, bucket_max_capacity/1.5
80
- #
91
+ #
81
92
  # set :hide_in_widgets, false
82
93
  # set :icon, "http://s3.amazonaws.com/icons/icon1.png"
83
94
  # end
@@ -95,7 +106,7 @@ network = Gamifier.dsl do
95
106
  set :active, true
96
107
  set :allow_duplicates, false
97
108
  end
98
-
109
+
99
110
  r_active_member = reward 'active member' do
100
111
  set :reward_template, {
101
112
  :message => "Looks like you like the site, thank you and keep up on being active on the site!"
@@ -123,7 +134,7 @@ network = Gamifier.dsl do
123
134
  set :active, true
124
135
  set :allow_duplicates, false
125
136
  end
126
-
137
+
127
138
  r_active_commenter = reward 'active commenter' do
128
139
  set :reward_template, {
129
140
  :message => "You have commented more than 3 times in any category!"
@@ -183,4 +194,4 @@ network = Gamifier.dsl do
183
194
  end
184
195
  end
185
196
 
186
- network.save!
197
+ network.save!
@@ -0,0 +1,19 @@
1
+ module Gamifier
2
+ module DSL
3
+ class ApiKey
4
+ attr_reader :source
5
+
6
+ def initialize(*args)
7
+ @source = ::Gamifier::ApiKey.new(*args)
8
+ end
9
+
10
+ def engine
11
+ source.engine
12
+ end
13
+
14
+ def method_missing(*args, &block)
15
+ source.send(*args, &block)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -6,28 +6,82 @@ module Gamifier
6
6
  extend Forwardable
7
7
  def_delegator :Gamifier, :engine, :engine
8
8
 
9
+ attr_reader :source
9
10
  attr_reader :sites
11
+ attr_reader :api_keys
10
12
 
11
- def initialize
12
- @sites = []
13
+ def initialize(*args)
14
+ @source = ::Gamifier::Network.new(*args)
15
+ @sites = []
16
+ @api_keys = []
17
+ end
18
+
19
+ def engine
20
+ @engine ||= Gamifier::Engine.new(:key => get_key('private') || Gamifier.config[:key])
21
+ end
22
+
23
+ def enterprise_engine
24
+ raise ArgumentError, "You must specify an enterprise key" unless Gamifier.config[:enterprise_key]
25
+ @enterprise_engine ||= Gamifier::Engine.new(:key => Gamifier.config[:enterprise_key])
13
26
  end
14
27
 
15
28
  def site(name, &block)
16
29
  new_site = DSL::Site.new(:name => name)
17
- new_site.source.engine = engine
18
30
  @sites.push(new_site)
19
31
 
20
32
  DSL.eval_with_context(new_site, &block)
21
33
  end
22
-
23
- def save!
34
+
35
+ def api_key(&block)
36
+ new_key = DSL::ApiKey.new
37
+ new_key.source.engine = enterprise_engine
38
+ @api_keys.push(new_key)
39
+
40
+ DSL.eval_with_context(new_key, &block)
41
+ end
42
+
43
+ def save_network!
44
+ begin
45
+ if self.save
46
+ save_api_keys!
47
+ end
48
+ rescue
49
+ Gamifier.logger.debug "Can't save #{self}"
50
+ end
51
+ end
52
+
53
+ def save_api_keys!
54
+ api_keys.each do |key|
55
+ key.engine = enterprise_engine
56
+ key.network_id = self.id
57
+ key.save
58
+ end
59
+ end
60
+
61
+ def save_sites!
24
62
  sites.each do |site|
25
63
  if gsite = engine.sites.find(site.url)
26
64
  site._id = gsite._id
27
65
  end
66
+ site.engine = engine
28
67
  site.save
29
68
  end
30
69
  end
70
+
71
+ def get_key(access = 'private')
72
+ key = self.api_keys.select {|k| k.access == access}.first
73
+ return key.key if key
74
+ nil
75
+ end
76
+
77
+ def save!
78
+ save_sites!
79
+ end
80
+
81
+ def method_missing(*args, &block)
82
+ source.send(*args, &block)
83
+ end
84
+
31
85
  end
32
86
  end
33
- end
87
+ end
@@ -78,6 +78,7 @@ module Gamifier
78
78
  # response, remove the next line:
79
79
  next
80
80
  end
81
+ unit.engine = engine
81
82
  unit.save || raise(Error, "Can't save #{unit}")
82
83
  end
83
84
  end
@@ -89,6 +90,7 @@ module Gamifier
89
90
  if gbehavior = engine.send(behavior.class.path).find_by_name(behavior.name, :site => self.url)
90
91
  behavior._id = gbehavior._id
91
92
  end
93
+ behavior.engine = engine
92
94
  behavior.save || raise(Error, "Can't save #{behavior}")
93
95
  end
94
96
  end
@@ -100,6 +102,7 @@ module Gamifier
100
102
  if greward = engine.send(reward.class.path).find_by_name(reward.name, :site => self.url)
101
103
  reward._id = greward._id
102
104
  end
105
+ reward.engine = engine
103
106
  reward.save || raise(Error, "Can't save #{reward}")
104
107
  end
105
108
  end
@@ -111,6 +114,7 @@ module Gamifier
111
114
  if gmission = engine.send(mission.class.path).find_by_name(mission.name, :site => self.url)
112
115
  mission._id = gmission._id
113
116
  end
117
+ mission.engine = engine
114
118
  mission.save || raise(Error, "Can't save #{mission}")
115
119
  end
116
120
  end
@@ -122,6 +126,7 @@ module Gamifier
122
126
  if gtrack = engine.send(track.class.path).find_by_label(track.label, :site => self.url)
123
127
  track._id = gtrack._id
124
128
  end
129
+ track.engine = engine
125
130
  track.save || raise(Error, "Can't save #{track}")
126
131
  end
127
132
  end
data/lib/gamifier/dsl.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'gamifier/dsl/network'
2
+ require 'gamifier/dsl/api_key'
2
3
  require 'gamifier/dsl/site'
3
4
 
4
5
  module Gamifier
@@ -12,7 +13,7 @@ module Gamifier
12
13
  new_context
13
14
  end
14
15
  end
15
-
16
+
16
17
  def set(key, *args, &block)
17
18
  if block
18
19
  self.send("#{key}=".to_sym, block)
@@ -21,4 +22,4 @@ module Gamifier
21
22
  end
22
23
  end
23
24
  end
24
- end
25
+ end
@@ -4,7 +4,7 @@ require 'gamifier/collection'
4
4
 
5
5
  module Gamifier
6
6
  class Engine
7
- MODELS = %w{Activity ActivityDefinition Group Player Reward RewardDefinition Site Track Unit User}
7
+ MODELS = %w{ApiKey Network Activity ActivityDefinition Group Player Reward RewardDefinition Site Track Unit User}
8
8
 
9
9
  attr_accessor :connection
10
10
  attr_writer :config
@@ -26,7 +26,11 @@ module Gamifier
26
26
  end
27
27
 
28
28
  def ok?
29
- !config.values_at(:key, :uri).any?{|k| k.nil? || k.empty?}
29
+ if config[:enterprise_key].nil? || config[:enterprise_key].empty?
30
+ !config.values_at(:key, :uri).any?{|k| k.nil? || k.empty?}
31
+ else
32
+ !(config[:uri].nil? || config[:uri].empty?)
33
+ end
30
34
  end
31
35
 
32
36
  # Sends an HTTP request corresponding to +method+, on +path+, with
@@ -65,8 +69,8 @@ module Gamifier
65
69
  end
66
70
  end
67
71
 
68
- def uri_to(path = "")
69
- URI.join(File.join(::Gamifier.config[:uri], ::Gamifier.config[:key], ""), path)
72
+ def uri_to(path = '')
73
+ URI.join(File.join(self.config[:uri], self.config[:key] || '', ''), path)
70
74
  end
71
75
 
72
76
  MODELS.each do |model|
@@ -0,0 +1,10 @@
1
+ require 'gamifier/model'
2
+
3
+ module Gamifier
4
+ class ApiKey < Model
5
+ def engine
6
+ raise ArgumentError, "You must specify an enterprise key" unless Gamifier.config[:enterprise_key]
7
+ @engine ||= Gamifier::Engine.new(:key => Gamifier.config[:enterprise_key])
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ require 'gamifier/model'
2
+
3
+ module Gamifier
4
+ class Network < Model
5
+ def engine
6
+ raise ArgumentError, "You must specify an enterprise key" unless Gamifier.config[:enterprise_key]
7
+ @engine ||= Gamifier::Engine.new(:key => Gamifier.config[:enterprise_key])
8
+ end
9
+ end
10
+ end
@@ -1,3 +1,3 @@
1
1
  module Gamifier
2
- VERSION = "1.0.8" unless defined?(Gamifier::VERSION)
2
+ VERSION = "1.1.0" unless defined?(Gamifier::VERSION)
3
3
  end
data/lib/gamifier.rb CHANGED
@@ -33,9 +33,9 @@ module Gamifier
33
33
 
34
34
  # Creates and returns a new DSL::Network object. The given block
35
35
  # will be evaluated in the context of the network object.
36
- #
36
+ #
37
37
  # Usage:
38
- #
38
+ #
39
39
  # network = Gamifier.dsl do
40
40
  # site 'my-site' do
41
41
  # set :url, 'my-site.com'
@@ -44,8 +44,7 @@ module Gamifier
44
44
  # end
45
45
  def dsl(&block)
46
46
  network = DSL::Network.new
47
- network.instance_eval(&block)
48
- network
47
+ DSL.eval_with_context(network, &block)
49
48
  end
50
49
 
51
50
  def logger
@@ -2,19 +2,19 @@ require 'spec_integration_helper'
2
2
 
3
3
  describe "managing collections" do
4
4
  before :all do
5
- @site = ENGINE.sites.find("ibadgedyou.dev")
5
+ @site = Gamifier.engine.sites.find("ibadgedyou.dev")
6
6
  @site.should_not be_nil
7
- ENGINE.activity_definitions.reset!(:site => "ibadgedyou.dev")
7
+ Gamifier.engine.activity_definitions.reset!(:site => "ibadgedyou.dev")
8
8
  end
9
9
 
10
10
  it "should list all players" do
11
11
  3.times do |i|
12
- behavior = ENGINE.activity_definitions.build({:selector => {:verb => "visit#{i}"}, :name => "visit#{i}", :site_id => @site._id}).save
12
+ behavior = Gamifier.engine.activity_definitions.build({:selector => {:verb => "visit#{i}"}, :name => "visit#{i}", :site_id => @site._id}).save
13
13
  behavior.should_not be_nil
14
14
  end
15
- ENGINE.activity_definitions.all(:site => "ibadgedyou.dev").length.should == 3
16
- ENGINE.activity_definitions.reset!(:site => "ibadgedyou.dev")
17
- ENGINE.activity_definitions.all(:site => "ibadgedyou.dev").length.should == 0
15
+ Gamifier.engine.activity_definitions.all(:site => "ibadgedyou.dev").length.should eq 3
16
+ Gamifier.engine.activity_definitions.reset!(:site => "ibadgedyou.dev")
17
+ Gamifier.engine.activity_definitions.all(:site => "ibadgedyou.dev").length.should eq 0
18
18
  end
19
19
 
20
20
  end
@@ -1,76 +1,72 @@
1
- require 'spec_integration_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe "DSL" do
4
- before do
5
- @network = Gamifier.dsl do
6
- site 'mydomain' do
7
- set :url, 'mydomain.com'
4
+
5
+ let(:url) { 'http://foo.com' }
6
+ let(:key) { '1234' }
7
+ let(:enterprise_key) { '5678' }
8
+ let(:network) {
9
+ Gamifier.dsl do
10
+ set :label, 'foo'
11
+ set :email, 'foo@bar.com'
12
+
13
+ api_key do
14
+ set :access, 'private'
15
+ end
16
+
17
+ site 'foo' do
18
+ set :url, 'bar.com'
8
19
 
9
20
  unit :karma do
10
- set :label, 'Karma'
21
+ set :label, 'karma'
11
22
  set :abbreviation, 'kar'
12
23
  end
24
+ end
13
25
 
14
- behavior 'new comment' do
15
- set :description, "new comment behaviour"
16
- set :selector, {
17
- :verb => 'new_comment',
18
- :category_id => 'hello'
19
- }
20
- set :adjustment, {
21
- :points => 15, :karma => 10
22
- }
23
-
24
- set :enable_count_limiting, true
25
- set :limit_per_player, 10
26
- set :limit_field_scope, 'category_id'
27
-
28
- set :enable_rate_limiting, true
29
- set :bucket_max_capacity, 2
30
- set :bucket_drain_rate, bucket_max_capacity/1.5
31
-
32
- set :hide_in_widgets, false
33
- set :icon, "http://crohr.me/images/cyrilrohr.jpg"
34
- end
26
+ end
27
+ }
35
28
 
29
+ let(:network_response) { '{"id":"5112257849f8387b000e85f6","label":"foo","email":"foo@bar.com","api_explorer_post":null,"permissions":{"api_explorer_posting":true,"social_mechanics":true,"read_only_widgets":true,"show_community_link":true},"attempts":20,"timeout":180,"whitelist_filter":null,"require_strong_passwords":false,"password_reset_in_days":60,"force_password_resets":false,"deny_previous_passwords":false,"enable_ip_whitelist":false}' }
30
+ let(:site_response) { '{"name":"foo","created_at":"2013-02-06T01:44:22-08:00","url":"bar.com","id":"511225f6297c011c62106fb7","_id":"511225f6297c011c62106fb7","network_id":"4fac5d4f3dc6483a0100000b","timed_reset":false,"reset_interval":null,"reset_month":null,"reset_date":null,"reset_day":null,"reset_hour":null,"interval_start":null,"interval_end":null}' }
31
+ let(:unit_response) { '{"id":"511226da297c011c4b11543e","name":"karma","label":"karma","normalized_name":"unit_karma","type":"point","abbreviation":"kar","display_priority":0}' }
36
32
 
37
- r1 = reward 'top commenter' do
38
- set :reward_template, {
39
- :message => "Congrats!"
40
- }
41
- set :components, [
42
- {:command => "count", :comparator => 1, :where => {:verb => 'new_comment', :player_id => "%player_id"}},
43
- # the first player who performs at least twice the 'new_question' behaviour
44
- {:command => "count", :comparator => {"$gt" => 2}, :where => {:verb => 'new_question', :site_id => "%site_id"}}
45
- ]
46
- set :adjustment, {
47
- :points => 5
48
- }
49
- set :active, true
50
- set :allow_duplicates, false
51
- end
52
-
53
- m1 = mission 'community member' do
54
- # allow a player to complete this mission more than once?
55
- set :repeatable, false
56
- set :active, true
57
- # give points and reward upon completing mission? (This is required for track progression)
58
- set :enable_rewards, true
59
- # points and secondary units to award when completing a mission
60
- set :adjustment, {
61
- :points => 10
62
- }
63
- set :reward_definition_ids do [r1._id] end
64
- end
65
-
66
- track 'commenting' do
67
- set :group_definition_ids do [m1._id] end
68
- end
69
- end
33
+ before do
34
+ stub_request(:get, "#{url}/#{key}/sites/bar.com.json").to_return(:status => 404, :body => '')
35
+ stub_request(:post, "#{url}/#{key}/sites.json").to_return(:status => 200, :body => site_response)
36
+ stub_request(:get, "#{url}/#{key}/units.json?page=1&per_page=50&site=bar.com").to_return(:status => 404, :body => '')
37
+ stub_request(:post, "#{url}/#{key}/units.json").to_return(:status => 200, :body => unit_response)
38
+ Gamifier.set :uri => url, :key => key, :enterprise_key => enterprise_key
39
+ end
40
+
41
+ context "when network already exists" do
42
+
43
+ let(:network_error_response) { '{"name":["is already taken"],"label":["is already taken"]}' }
44
+
45
+ before do
46
+ stub_request(:post, "#{url}/#{enterprise_key}/networks.json").to_return(:status => 422, :body => network_error_response)
47
+ end
48
+
49
+ it { expect { network.save_network! }.to_not raise_error }
50
+
51
+ end
52
+
53
+ context "when network does not exists" do
54
+
55
+ let(:api_key_response) { '{"id":"51122b073dc6480b760f66ce","network_id":"5112257849f8387b000e85f6","key":"5c3782a61ff639c92c30ea73d294e25e","access":"private","enable_whitelist":false,"ip_addresses":null}' }
56
+
57
+ before do
58
+ stub_request(:post, "#{url}/#{enterprise_key}/networks.json").to_return(:status => 200, :body => network_response)
59
+ stub_request(:post, "#{url}/#{enterprise_key}/api_keys.json").to_return(:status => 200, :body => api_key_response)
70
60
  end
61
+
62
+ it { expect { network.save_network! }.to_not raise_error }
63
+
71
64
  end
65
+
66
+ it { expect{ network.save! }.to_not raise_error }
67
+
72
68
  it "should work twice" do
73
- expect{ @network.save! }.to_not raise_error
74
- expect{ @network.save! }.to_not raise_error
69
+ expect{ network.save! }.to_not raise_error
70
+ expect{ network.save! }.to_not raise_error
75
71
  end
76
- end
72
+ end
@@ -1,23 +1,25 @@
1
1
  require 'spec_integration_helper'
2
2
 
3
3
  describe "managing players" do
4
- before :all do
4
+
5
+ before do
5
6
  destroy_test_player!
6
7
  end
7
8
 
8
9
  it "should list all players" do
9
- players = ENGINE.players.all
10
+ players = Gamifier.engine.players.all
10
11
  players.all?{|p| p.kind_of?(Gamifier::Player)}.should be_true
11
12
  end
12
13
 
13
14
  it "should create a new player" do
14
15
  find_or_create_test_user
15
- player = ENGINE.players.build(player_attributes)
16
+ player = Gamifier.engine.players.build(player_attributes)
16
17
  player.save
17
- ENGINE.players.find(player._id).should_not be_nil
18
+ Gamifier.engine.players.find(player._id).should_not be_nil
18
19
  end
19
20
 
20
21
  describe "with an existing player" do
22
+
21
23
  before do
22
24
  @player = find_or_create_test_player
23
25
  end
@@ -34,8 +36,9 @@ describe "managing players" do
34
36
  url = "http://s3.amazonaws.com/crohr.dimelo/identity_avatars/2ffbf54be4af49e7/avatar_normal.png?f59510d"
35
37
  @player.picture_url = url
36
38
  @player.save.should be_true
37
- ENGINE.players.find(@player._id).picture_url.should == url
39
+ Gamifier.engine.players.find(@player._id).picture_url.should == url
38
40
  end
41
+
39
42
  end
40
43
 
41
44
  end
@@ -2,18 +2,27 @@ require 'spec_integration_helper'
2
2
 
3
3
  describe "managing users" do
4
4
 
5
- before :all do
6
- user = ENGINE.users.find(user_attributes[:email])
7
- if user
8
- puts "Found user #{user}. Deleting..."
9
- user.destroy.should be_true
10
- end
5
+ let(:url) { 'http://foo.com' }
6
+ let(:key) { '1234' }
7
+
8
+ before do
9
+ Gamifier.set :uri => url, :key => key
11
10
  end
12
11
 
13
- it "should create a new user" do
14
- user = ENGINE.users.build(user_attributes)
15
- user.should be_new
16
- user.save.should be_true
17
- user.should_not be_new
12
+ context "when user does not exists" do
13
+
14
+ let(:user) { Gamifier.engine.users.build(user_attributes) }
15
+ let(:users_response) { '"name": "Foo Bar","created_at": "2013-02-12T06:13:50-08:00","email": "user@foo.com","_id": "511a4e1e297c0148ed00238c","id": "511a4e1e297c0148ed00238c"' }
16
+
17
+ before do
18
+ stub_request(:post, "#{url}/#{key}/users.json").to_return(:status => 200, :body => users_response)
19
+ end
20
+
21
+ subject { user }
22
+
23
+ it { should be_new }
24
+ it { subject.save.should be_true }
25
+
18
26
  end
19
- end
27
+
28
+ end