ribose 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -23,7 +23,7 @@ module Ribose
23
23
  end
24
24
 
25
25
  def request_body(attributes)
26
- custom_option.merge(resource_key.to_sym => validate(attributes))
26
+ custom_option.merge(resource_key.to_sym => validate(**attributes))
27
27
  end
28
28
 
29
29
  def create_resource
data/lib/ribose/client.rb CHANGED
@@ -1,14 +1,9 @@
1
1
  module Ribose
2
2
  class Client
3
- attr_accessor :api_token, :api_email, :user_email,
4
- :client_id, :uid, :access_token
3
+ attr_accessor :api_email, :api_token, :access_token, :uid, :client_id
5
4
 
6
5
  def initialize(options = {})
7
- @api_token = options.fetch(:api_token, configuration.api_token).to_s
8
- @api_email = options.fetch(:api_email, configuration.api_email).to_s
9
- @client_id = options[:client_id]
10
- @uid = options[:uid]
11
- @access_token = options[:access_token]
6
+ initialize_client_details(options)
12
7
  end
13
8
 
14
9
  # Initiate a ribose client
@@ -23,20 +18,17 @@ module Ribose
23
18
  # @param :api_token [String] The authentication token for your API account
24
19
  # @return [Ribose::Client] A new client with your details
25
20
  #
26
- def self.from_login(email:, password:, api_email:, api_token:)
27
- session = Session.create(
28
- username: email,
29
- password: password,
30
- api_email: api_email,
31
- api_token: api_token
21
+ def self.from_login(email:, password:)
22
+ session = Ribose::Session.create(
23
+ username: email, password: password,
32
24
  )
33
25
 
34
26
  new(
35
- api_email: api_email,
36
- api_token: api_token,
37
- client_id: session.nil? ? nil : session['client'],
38
- uid: session.nil? ? nil : session['uid'],
39
- access_token: session.nil? ? nil : session['access-token'],
27
+ api_email: email,
28
+ uid: session.uid,
29
+ client_id: session.client,
30
+ api_token: session["access-token"],
31
+ access_token: session["access-token"],
40
32
  )
41
33
  end
42
34
 
@@ -45,5 +37,13 @@ module Ribose
45
37
  def configuration
46
38
  Ribose.configuration
47
39
  end
40
+
41
+ def initialize_client_details(options)
42
+ @uid = options.fetch(:uid, nil)
43
+ @client_id = options.fetch(:client_id, nil)
44
+ @access_token = options.fetch(:access_token, nil)
45
+ @api_email = options.fetch(:api_email, configuration.api_email)
46
+ @api_token = options.fetch(:api_token, configuration.api_token)
47
+ end
48
48
  end
49
49
  end
@@ -2,15 +2,13 @@ require "ribose/response/raise_error"
2
2
 
3
3
  module Ribose
4
4
  class Configuration
5
- attr_accessor :api_host, :api_email, :api_token,
6
- :user_email, :user_password,
7
- :verify_ssl,
8
- :debug_mode
5
+ attr_accessor :api_email, :verify_ssl, :client, :api_host,
6
+ :api_token, :user_email, :user_password, :debug_mode
9
7
 
10
8
  def initialize
11
9
  @debug_mode = false
12
10
  @verify_ssl = true
13
- @api_host ||= "https://www.ribose.com"
11
+ @api_host ||= "www.ribose.com"
14
12
  end
15
13
 
16
14
  def debug_mode?
@@ -21,8 +19,14 @@ module Ribose
21
19
  !!verify_ssl
22
20
  end
23
21
 
24
- def ssl_verification_mode
25
- verify_ssl? ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE
22
+ def api_email
23
+ @user_email || @api_email
24
+ end
25
+
26
+ def client
27
+ @client ||= Ribose::Client.from_login(
28
+ email: api_email, password: user_password,
29
+ )
26
30
  end
27
31
 
28
32
  def add_default_middleware(builder)
@@ -30,5 +34,9 @@ module Ribose
30
34
  builder.response(:logger, nil, bodies: true) if debug_mode?
31
35
  builder.adapter(Faraday.default_adapter)
32
36
  end
37
+
38
+ def ssl_verification_mode
39
+ verify_ssl? ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE
40
+ end
33
41
  end
34
42
  end
data/lib/ribose/event.rb CHANGED
@@ -12,7 +12,7 @@ module Ribose
12
12
  # @return [Sawyer::Resource] Calendar Events
13
13
  #
14
14
  def self.all(calendar_id, options = {})
15
- Ribose::Calendar.fetch(calendar_id, options)
15
+ Ribose::Calendar.fetch(calendar_id, **options)
16
16
  end
17
17
 
18
18
  # Fetch a calendar event
@@ -31,7 +31,7 @@ module Ribose
31
31
  # @param attributes [Hash] Attributes as a Hash
32
32
  # @return [Sawyer::Resource] File upload response.
33
33
  def self.upload(space_id, file:, **attributes)
34
- new(space_id, attributes.merge(file: file)).create
34
+ new(space_id, **attributes.merge(file: file)).create
35
35
  end
36
36
 
37
37
  private
@@ -16,12 +16,11 @@ module Ribose
16
16
  # @returns [Sawyer::Resource] The file version
17
17
  #
18
18
  def self.fetch(space_id:, file_id:, version_id:, **options)
19
- new(
20
- file_id: file_id,
21
- space_id: space_id,
22
- resource_id: version_id,
23
- **options,
24
- ).fetch
19
+ options = options.merge(
20
+ file_id: file_id, space_id: space_id, resource_id: version_id,
21
+ )
22
+
23
+ new(options).fetch
25
24
  end
26
25
 
27
26
  # Download file version
@@ -32,12 +31,11 @@ module Ribose
32
31
  # @param options [Hash] Options as key and value pair
33
32
  #
34
33
  def self.download(space_id, file_id, version_id:, **options)
35
- new(
36
- file_id: file_id,
37
- space_id: space_id,
38
- resource_id: version_id,
39
- **options,
40
- ).download
34
+ options = options.merge(
35
+ file_id: file_id,space_id: space_id, resource_id: version_id,
36
+ )
37
+
38
+ new(options).download
41
39
  end
42
40
 
43
41
  # Create a new file version
@@ -49,10 +47,8 @@ module Ribose
49
47
  # @return [Sawyer::Resource] Newly updated version
50
48
  #
51
49
  def self.create(space_id, file_id, file:, **attributes)
52
- upload = VersionUploader.upload(
53
- space_id, file_id, attributes.merge(file: file)
54
- )
55
-
50
+ attributes = attributes.merge(file: file)
51
+ upload = VersionUploader.upload(space_id, file_id, **attributes)
56
52
  upload[:attachment]
57
53
  end
58
54
 
@@ -1,7 +1,7 @@
1
1
  module Ribose
2
2
  class Request
3
-
4
3
  DEFAULT_CONTENT_TYPE = "application/json"
4
+
5
5
  # Initialize a Request
6
6
  #
7
7
  # @param http_method [Symbol] HTTP verb as sysmbol
@@ -9,7 +9,7 @@ module Ribose
9
9
  # @param data [Hash] Attributes / Options as a Hash
10
10
  # @return [Ribose::Request]
11
11
  #
12
- def initialize(http_method, endpoint, **data)
12
+ def initialize(http_method, endpoint, data = {})
13
13
  @data = data
14
14
  @endpoint = endpoint
15
15
  @http_method = http_method
@@ -26,11 +26,7 @@ module Ribose
26
26
  options[:query] = extract_config_option(:query) || {}
27
27
 
28
28
  response = agent.call(http_method, api_endpoint, data, options)
29
-
30
- # update client headers from response
31
- client.client_id = response.headers['client']
32
- client.uid = response.headers['uid']
33
- client.access_token = response.headers['access-token']
29
+ update_client_headers(response.headers)
34
30
 
35
31
  parsable == true ? response.data : response
36
32
  end
@@ -79,7 +75,7 @@ module Ribose
79
75
  attr_reader :client, :data, :http_method
80
76
 
81
77
  def ribose_host
82
- Ribose.configuration.api_host.host
78
+ Ribose.configuration.api_host
83
79
  end
84
80
 
85
81
  def extract_config_option(key)
@@ -89,13 +85,7 @@ module Ribose
89
85
  end
90
86
 
91
87
  def find_suitable_client
92
- # client = extract_config_option(:client) || Ribose::Client.new
93
- client = extract_config_option(:client) ||
94
- Ribose::Client.from_login(
95
- email: Ribose.configuration.user_email,
96
- password: Ribose.configuration.user_password,
97
- api_token: Ribose.configuration.api_token
98
- )
88
+ client = extract_config_option(:client) || Ribose.configuration.client
99
89
  client.is_a?(Ribose::Client) ? client : raise(Ribose::Unauthorized)
100
90
  end
101
91
 
@@ -119,13 +109,12 @@ module Ribose
119
109
  unless Ribose.configuration.verify_ssl?
120
110
  faraday_options.merge!(ssl: Faraday::SSLOptions.new(
121
111
  false, nil, nil, OpenSSL::SSL::VERIFY_NONE
122
- )
123
- )
112
+ ))
124
113
  end
125
114
 
126
115
  {
127
- links_parser: Sawyer::LinkParsers::Simple.new,
128
116
  faraday: Faraday.new(faraday_options),
117
+ links_parser: Sawyer::LinkParsers::Simple.new,
129
118
  }
130
119
  end
131
120
 
@@ -135,21 +124,10 @@ module Ribose
135
124
  end
136
125
  end
137
126
 
138
- def set_content_type(headers)
139
- header = custom_content_headers
140
-
141
- headers[:content_type] = DEFAULT_CONTENT_TYPE
142
- headers[:accept] = header.fetch(:accept, DEFAULT_CONTENT_TYPE)
143
- end
144
-
145
127
  def agent
146
128
  @agent ||= Sawyer::Agent.new(ribose_host, sawyer_options) do |http|
147
129
  set_content_type(http.headers)
148
-
149
- # set headers for devise-token-auth
150
- http.headers["access-token"] = client.access_token
151
- http.headers["client"] = client.client_id
152
- http.headers["uid"] = client.uid
130
+ set_devise_specific_headers(http.headers)
153
131
 
154
132
  if require_auth_headers?
155
133
  http.headers["X-Indigo-Token"] = client.api_token
@@ -157,5 +135,24 @@ module Ribose
157
135
  end
158
136
  end
159
137
  end
138
+
139
+ def update_client_headers(headers)
140
+ client.uid = headers["uid"]
141
+ client.client_id = headers["client"]
142
+ client.access_token = headers["access-token"]
143
+ end
144
+
145
+ def set_content_type(headers)
146
+ headers[:content_type] = DEFAULT_CONTENT_TYPE
147
+ headers[:accept] = custom_content_headers.fetch(
148
+ :accept, DEFAULT_CONTENT_TYPE
149
+ )
150
+ end
151
+
152
+ def set_devise_specific_headers(headers)
153
+ headers["uid"] = client.uid
154
+ headers["client"] = client.client_id
155
+ headers["access-token"] = client.access_token
156
+ end
160
157
  end
161
158
  end
@@ -3,8 +3,6 @@ require "ribose/error"
3
3
  module Ribose
4
4
  module Response
5
5
  class RaiseError < Faraday::Response::Middleware
6
- private
7
-
8
6
  def on_complete(response)
9
7
  if error = Ribose::Error.from_response(response)
10
8
  raise error
@@ -1,62 +1,72 @@
1
- require "json"
2
- require 'net/http'
3
- require 'uri'
4
- require "ribose/config"
1
+ require "uri"
2
+ require "ostruct"
3
+ require "net/http"
5
4
 
6
5
  module Ribose
7
6
  class Session
8
- def initialize(username, password, api_email, api_token)
9
- @username = username
10
- @password = password
11
- @api_email = api_email
12
- @api_token = api_token
7
+ def initialize(username, password)
8
+ @username = username
9
+ @password = password
13
10
  end
14
11
 
15
12
  def create
16
13
  authenticate_user
14
+ rescue NoMethodError, JSON::ParserError
15
+ raise Ribose::Unauthorized
17
16
  end
18
17
 
19
- def self.create(username:, password:, api_email:, api_token:)
20
- new(username, password, api_email, api_token).create
18
+ def self.create(username:, password:)
19
+ new(username, password).create
21
20
  end
22
21
 
23
22
  private
24
23
 
25
- attr_reader :username, :password, :api_email, :api_token
24
+ attr_reader :username, :password
26
25
 
27
26
  def authenticate_user
28
- uri = URI.parse(ribose_url_for("api/v2/auth/sign_in"))
29
- response = Net::HTTP.start(
30
- uri.host,
31
- uri.port,
32
- use_ssl: true,
33
- verify_mode: Ribose.configuration.ssl_verification_mode
34
- ) do |http|
35
- request = Net::HTTP::Post.new(uri)
36
- # set request headers
37
- request['X-Indigo-Username'] = api_email
38
- request['X-Indigo-Token'] = api_token
39
- request['Content-Type'] = 'application/json'
40
-
41
- # set form data
42
- request.set_form_data(
43
- 'username' => username,
44
- 'password' => password
45
- )
27
+ response = submit_user_login_request
28
+
29
+ case response
30
+ when Net::HTTPSuccess
31
+ build_session_data(response.each_header.to_h)
32
+ when Net::HTTPForbidden
33
+ raise(Ribose::Unauthorized)
34
+ end
35
+ end
36
+
37
+ def submit_user_login_request
38
+ Net::HTTP.start(login_uri.host, login_uri.port, http_options) do |http|
39
+ request = Net::HTTP::Post.new(login_uri)
40
+
41
+ request["Content-Type"] = "application/json"
42
+ request.set_form_data(username: username, password: password)
43
+
46
44
  http.request(request)
47
45
  end
46
+ end
48
47
 
49
- # return response headers in hash if success
50
- return response.each_header.to_h if response.is_a? Net::HTTPSuccess
51
- nil
48
+ def api_host
49
+ api_host = Ribose.configuration.api_host
50
+
51
+ unless api_host[/\Ahttp:\/\//] || api_host[/\Ahttps:\/\//]
52
+ "https://#{api_host}"
53
+ end
54
+ end
55
+
56
+ def login_uri
57
+ @login_uri ||= URI.parse([api_host, "api/v2/auth/sign_in"].join("/"))
52
58
  end
53
59
 
54
- def agent
55
- @agent ||= Mechanize.new
60
+ def http_options
61
+ { use_ssl: true, verify_ssl: Ribose.configuration.ssl_verification_mode }
56
62
  end
57
63
 
58
- def ribose_url_for(*endpoint)
59
- [Ribose.configuration.api_host, *endpoint].join("/")
64
+ def build_session_data(headers)
65
+ SessionData.new(headers.slice("uid", "expiry", "client", "access-token"))
60
66
  end
61
67
  end
68
+
69
+ class SessionData < ::OpenStruct
70
+ alias :read_attribute_for_serialization :send
71
+ end
62
72
  end
@@ -57,7 +57,7 @@ module Ribose
57
57
  # @return [Sawyer::Resource] The file upload response.
58
58
  #
59
59
  def self.create(space_id, file:, **attributes)
60
- upload = FileUploader.upload(space_id, attributes.merge(file: file))
60
+ upload = FileUploader.upload(space_id, **attributes.merge(file: file))
61
61
  upload[:attachment]
62
62
  end
63
63
 
@@ -1,3 +1,3 @@
1
1
  module Ribose
2
- VERSION = "0.4.1".freeze
2
+ VERSION = "0.5.0".freeze
3
3
  end
@@ -8,7 +8,7 @@ module Ribose
8
8
  end
9
9
 
10
10
  def self.upload(space_id, file_id, file:, **attributes)
11
- new(space_id, file_id, attributes.merge(file: file)).create
11
+ new(space_id, file_id, **attributes.merge(file: file)).create
12
12
  end
13
13
 
14
14
  private
data/ribose.gemspec CHANGED
@@ -28,5 +28,5 @@ Gem::Specification.new do |spec|
28
28
  spec.add_development_dependency "rake"
29
29
  spec.add_development_dependency "rspec", "~> 3.0"
30
30
  spec.add_development_dependency "pry"
31
- spec.add_development_dependency "webmock", "~> 2.0"
31
+ spec.add_development_dependency "webmock", "~> 3.0"
32
32
  end
@@ -7,42 +7,41 @@ RSpec.describe Ribose::Client do
7
7
  client = Ribose::Client.new
8
8
 
9
9
  expect(client.api_token).to eq(Ribose.configuration.api_token)
10
- expect(client.user_email).to eq(Ribose.configuration.user_email)
10
+ expect(client.api_email).to eq(Ribose.configuration.api_email)
11
11
  end
12
12
  end
13
13
 
14
14
  context "custom attribtues provided" do
15
15
  it "initialize with the supplied attribtues" do
16
- client = Ribose::Client.new(token: 123, email: "john@ex.com")
16
+ email = "john@ex.com"
17
+ token = "SECRET_API_TOKEN"
18
+ client = Ribose::Client.new(api_token: token, api_email: email)
17
19
 
18
- expect(client.api_token).to eq("123")
19
- expect(client.user_email).to eq("john@ex.com")
20
+ expect(client.api_token).to eq(token)
21
+ expect(client.api_email).to eq(email)
20
22
  end
21
23
  end
22
24
  end
23
25
 
24
26
  describe ".from_login" do
25
27
  it "authenticate the user and build a client" do
26
- email = "useremail@example..com"
27
- password = "supersecretpassword"
28
+ email = "user.email@gmail.com"
29
+ password = "supser.secrect.password"
28
30
 
29
- allow(Ribose::Session).to receive(:create).and_return(session_hash)
31
+ allow(Ribose::Session).to receive(:create).and_return(session)
30
32
  client = Ribose::Client.from_login(email: email, password: password)
31
33
 
32
- expect(client.user_email).to eq(email)
33
- expect(client.api_token).to eq(session_hash["authentication_token"])
34
+ expect(client.api_email).to eq(email)
35
+ expect(client.uid).to eq(session.uid)
36
+ expect(client.client_id).to eq(session.client)
34
37
  end
35
38
  end
36
39
 
37
- def session_hash
38
- {
39
- "authentication_token" => "SecretToken",
40
- "last_activity" => {
41
- "id" => 122072207,
42
- "session_id" => "SessionId",
43
- "browser" => "Ribose Ruby Client",
44
- "user_id" => "user-uuid-123-4567"
45
- },
46
- }
40
+ def session
41
+ @session ||= Ribose::SessionData.new(
42
+ uid: "hello",
43
+ expiry: Time.now + 3600,
44
+ client: "RIBOSE_RUBY_CLIENT",
45
+ )
47
46
  end
48
47
  end
@@ -20,7 +20,6 @@ RSpec.describe Ribose::Config do
20
20
  expect(Ribose.configuration.debug_mode?).to be_falsey
21
21
  expect(Ribose.configuration.api_token).to eq(api_token)
22
22
  expect(Ribose.configuration.user_email).to eq(user_email)
23
- expect(Ribose.configuration.web_url).to eq ["https", api_host].join("://")
24
23
  end
25
24
  end
26
25
 
@@ -7,7 +7,7 @@ RSpec.describe Ribose::FileUploader do
7
7
  space_id = 123_456_789
8
8
 
9
9
  stub_ribose_space_file_upload_api(space_id, file_attributes)
10
- file_upload = Ribose::FileUploader.upload(space_id, file_attributes)
10
+ file_upload = Ribose::FileUploader.upload(space_id, **file_attributes)
11
11
 
12
12
  expect(file_upload.attachment.id).not_to be_nil
13
13
  expect(file_upload.attachment.author).to eq("John Doe")
@@ -21,7 +21,7 @@ RSpec.describe Ribose::FileUploader do
21
21
  attributes = file_attributes(File.join(Ribose.root, "Rakefile"))
22
22
 
23
23
  stub_ribose_space_file_upload_api(space_id, attributes)
24
- file_upload = Ribose::FileUploader.upload(space_id, attributes)
24
+ file_upload = Ribose::FileUploader.upload(space_id, **attributes)
25
25
 
26
26
  expect(file_upload.attachment.id).not_to be_nil
27
27
  expect(file_upload.attachment.author).to eq("John Doe")
@@ -47,7 +47,7 @@ RSpec.describe Ribose::FileVersion do
47
47
  space_id = 456_789
48
48
 
49
49
  stub_ribose_space_file_upload_api(space_id, file_attributes, file_id)
50
- file = Ribose::FileVersion.create(space_id, file_id, file_attributes)
50
+ file = Ribose::FileVersion.create(space_id, file_id, **file_attributes)
51
51
 
52
52
  expect(file.id).not_to be_nil
53
53
  expect(file.author).to eq("John Doe")
@@ -20,9 +20,10 @@ RSpec.describe Ribose::Message do
20
20
  describe ".create" do
21
21
  it "creates a new message into a conversation" do
22
22
  space_id = 123_456
23
+ message_attributes = message_attrs.merge(space_id: space_id)
23
24
 
24
25
  stub_ribose_message_create(space_id, message: message_attrs)
25
- message = Ribose::Message.create(message_attrs.merge(space_id: space_id))
26
+ message = Ribose::Message.create(**message_attributes)
26
27
 
27
28
  expect(message.id).not_to be_nil
28
29
  expect(message.user.name).to eq("John Doe")
@@ -37,7 +38,7 @@ RSpec.describe Ribose::Message do
37
38
 
38
39
  stub_ribose_message_update(space_id, message_id, message: message_attrs)
39
40
  message = Ribose::Message.update(
40
- message_attrs.merge(space_id: space_id, message_id: message_id),
41
+ **message_attrs.merge(space_id: space_id, message_id: message_id),
41
42
  )
42
43
 
43
44
  expect(message.user.name).to eq("John Doe")
@@ -6,41 +6,35 @@ RSpec.describe Ribose::Session do
6
6
  username = "super.user"
7
7
  password = "supper.secreet.password"
8
8
 
9
- stub_session_creation_request_via_web
9
+ stub_post_signin_request
10
10
  session = Ribose::Session.create(username: username, password: password)
11
11
 
12
- expect(session["created_at"]).not_to be_nil
13
- expect(session["authentication_token"]).to eq("user-super-secret-token")
12
+ expect(session.uid).to eq(session_headers["uid"])
13
+ expect(session.client).to eq(session_headers["client"])
14
+ expect(session["access-token"]).to eq(session_headers["access-token"])
14
15
  end
15
16
  end
16
17
 
17
- def login_url
18
- ribose_url_for("api/v2/auth/sign_in")
19
- end
20
-
21
- def ribose_url_for(*endpoints)
22
- [Ribose.configuration.api_host, *endpoints].join("/")
18
+ def session_headers
19
+ @session_headers ||= {
20
+ "uid" => "user@example.com",
21
+ "expiry" => Time.now,
22
+ "client" => "sample-user-client",
23
+ "access-token" => "super.secret.access.token",
24
+ }
23
25
  end
24
26
 
25
- def stub_session_creation_request_via_web
26
- stub_get_request_with_login_page
27
- stub_post_request_with_empty_body
28
- stub_general_inforomation_request
29
- end
30
-
31
- def stub_get_request_with_login_page
32
- stub_request(:get, login_url).and_return(
33
- body: ribose_fixture("login", "html"),
34
- headers: { content_type: "text/html" },
27
+ def stub_post_signin_request
28
+ stub_request(:post, login_url).and_return(
29
+ body: ribose_fixture("empty"), headers: session_headers,
35
30
  )
36
31
  end
37
32
 
38
- def stub_general_inforomation_request
39
- stub_request(:get, ribose_url_for(["settings", "general", "info"])).
40
- and_return(body: ribose_fixture("general_information"), status: 200)
33
+ def login_url
34
+ [api_host, "api/v2/auth/sign_in"].join("/")
41
35
  end
42
36
 
43
- def stub_post_request_with_empty_body
44
- stub_request(:post, login_url).and_return(body: ribose_fixture("empty"))
37
+ def api_host
38
+ "https://#{Ribose.configuration.api_host}"
45
39
  end
46
40
  end
@@ -64,7 +64,7 @@ RSpec.describe Ribose::SpaceFile do
64
64
  space_id = 123_456_789
65
65
 
66
66
  stub_ribose_space_file_upload_api(space_id, file_attributes)
67
- file = Ribose::SpaceFile.create(space_id, file_attributes)
67
+ file = Ribose::SpaceFile.create(space_id, **file_attributes)
68
68
 
69
69
  expect(file.id).not_to be_nil
70
70
  expect(file.author).to eq("John Doe")
@@ -28,7 +28,7 @@ RSpec.describe Ribose::Space do
28
28
  describe ".create" do
29
29
  it "creates a new space with provided details" do
30
30
  stub_ribose_space_create_api(space_attributes)
31
- space = Ribose::Space.create(space_attributes)
31
+ space = Ribose::Space.create(**space_attributes)
32
32
 
33
33
  expect(space.id).not_to be_nil
34
34
  expect(space.visibility).to eq("invisible")