facemock 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/.coveralls.yml +1 -0
  2. data/.gitignore +22 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +6 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +154 -0
  8. data/Rakefile +6 -0
  9. data/db/.gitkeep +0 -0
  10. data/facemock.gemspec +31 -0
  11. data/lib/facemock/config.rb +88 -0
  12. data/lib/facemock/database/application.rb +20 -0
  13. data/lib/facemock/database/permission.rb +21 -0
  14. data/lib/facemock/database/table.rb +340 -0
  15. data/lib/facemock/database/user.rb +26 -0
  16. data/lib/facemock/database.rb +121 -0
  17. data/lib/facemock/errors.rb +7 -0
  18. data/lib/facemock/fb_graph/application/test_users.rb +36 -0
  19. data/lib/facemock/fb_graph/application/user/permission.rb +10 -0
  20. data/lib/facemock/fb_graph/application/user.rb +69 -0
  21. data/lib/facemock/fb_graph/application.rb +48 -0
  22. data/lib/facemock/fb_graph/user.rb +13 -0
  23. data/lib/facemock/fb_graph.rb +30 -0
  24. data/lib/facemock/version.rb +3 -0
  25. data/lib/facemock.rb +19 -0
  26. data/spec/facemock/config_spec.rb +185 -0
  27. data/spec/facemock/database/application_spec.rb +73 -0
  28. data/spec/facemock/database/permission_spec.rb +52 -0
  29. data/spec/facemock/database/tables_spec.rb +728 -0
  30. data/spec/facemock/database/user_spec.rb +169 -0
  31. data/spec/facemock/database_spec.rb +270 -0
  32. data/spec/facemock/errors_spec.rb +9 -0
  33. data/spec/facemock/fb_graph/application/test_users_spec.rb +155 -0
  34. data/spec/facemock/fb_graph/application/user_spec.rb +208 -0
  35. data/spec/facemock/fb_graph/application_spec.rb +132 -0
  36. data/spec/facemock/fb_graph/user_spec.rb +36 -0
  37. data/spec/facemock/fb_graph_spec.rb +47 -0
  38. data/spec/facemock_spec.rb +74 -0
  39. data/spec/spec_helper.rb +18 -0
  40. data/spec/support/tables_helper.rb +46 -0
  41. metadata +64 -3
@@ -0,0 +1,340 @@
1
+ require 'facemock/database'
2
+ require 'sqlite3'
3
+ require 'hashie'
4
+
5
+ module Facemock
6
+ class Database
7
+ class Table
8
+ # 以下は継承先でオーバーライド必須
9
+ # * TABLE_NAME, COLUMN_NAMES
10
+ # * initialize()
11
+ TABLE_NAME = :tables
12
+ COLUMN_NAMES = [:id, :text, :active, :number, :created_at]
13
+
14
+ def initialize(options={})
15
+ opts = Hashie::Mash.new(options)
16
+ self.id = opts.id
17
+ self.text = opts.text
18
+ self.active = opts.active || false
19
+ self.number = opts.number
20
+ self.created_at = opts.created_at
21
+ end
22
+
23
+ def save!(options={})
24
+ persisted? ? update!(options) : insert!(options)
25
+ end
26
+
27
+ def update_attributes!(options)
28
+ # カラムに含まれるかどうかの確認。なければNoMethodError
29
+ options.each_key {|key| self.send(key) }
30
+ if persisted?
31
+ update!(options)
32
+ else
33
+ insert!(options)
34
+ end
35
+ end
36
+
37
+ def destroy
38
+ raise unless persisted?
39
+ execute "DELETE FROM #{table_name} WHERE ID = #{self.id};"
40
+ self
41
+ end
42
+
43
+ def fetch
44
+ if persisted?
45
+ sql = "SELECT * FROM #{table_name} WHERE ID = #{self.id} LIMIT 1;"
46
+ records = execute sql
47
+ return nil unless record = records.first
48
+ set_attributes_from_record(record)
49
+ self
50
+ end
51
+ end
52
+
53
+ def method_missing(name, *args)
54
+ method_name = name.to_s.include?("=") ? name.to_s[0...-1].to_sym : name
55
+ case name
56
+ when :identifier then return send(:id)
57
+ when :identifier= then return send(:id=, *args)
58
+ else
59
+ if column_names.include?(method_name) && args.size <= 1
60
+ if !name.to_s.include?("=") && args.empty?
61
+ define_column_getter(name)
62
+ return send(name)
63
+ else
64
+ define_column_setter(name)
65
+ return send(name, args.first)
66
+ end
67
+ else
68
+ super
69
+ end
70
+ end
71
+ end
72
+
73
+ def self.all
74
+ records = execute "SELECT * FROM #{table_name};"
75
+ records_to_objects(records)
76
+ end
77
+
78
+ def self.first
79
+ records = execute "SELECT * FROM #{table_name} LIMIT 1;"
80
+ record_to_object(records.first)
81
+ end
82
+
83
+ def self.last
84
+ records = execute "SELECT * FROM #{table_name} ORDER BY ID DESC LIMIT 1 ;"
85
+ record_to_object(records.first)
86
+ end
87
+
88
+ def self.where(column)
89
+ column_name = column.keys.first
90
+ value = column.values.first
91
+ column_value = (value.kind_of?(String)) ? "'" + value + "'" : value.to_s
92
+
93
+ records = execute "SELECT * FROM #{table_name} WHERE #{column_name} = #{column_value};"
94
+ records_to_objects(records)
95
+ end
96
+
97
+ def self.method_missing(name, *args)
98
+ if name =~ /^find_by_(.+)/ || name =~ /^find_all_by_(.+)/
99
+ column_name = $1
100
+ else
101
+ super
102
+ end
103
+ super unless column_names.include?(column_name.to_sym)
104
+ raise ArgumentError, "wrong number of arguments (#{args.size} for 1)" unless args.size == 1
105
+ super unless define_find_method(name, column_name)
106
+ send(name, args.first)
107
+ end
108
+
109
+ def table_name
110
+ self.class.table_name
111
+ end
112
+
113
+ def column_names
114
+ self.class.column_names
115
+ end
116
+
117
+ def persisted?
118
+ !!(self.id && !(self.class.find_by_id(self.id).nil?))
119
+ end
120
+
121
+ def self.table_name
122
+ self::TABLE_NAME
123
+ end
124
+
125
+ def self.column_names
126
+ self::COLUMN_NAMES
127
+ end
128
+
129
+ def self.column_type(column_name)
130
+ return nil unless column_names.include?(column_name.to_s.to_sym)
131
+ table_info.send(column_name).type
132
+ end
133
+
134
+ def self.table_info
135
+ sql = "PRAGMA TABLE_INFO(#{table_name});"
136
+ records = execute sql
137
+ info = Hashie::Mash.new
138
+ records.each do |record|
139
+ column_info = Hashie::Mash.new(
140
+ { cid: record[0],
141
+ name: record[1].to_sym,
142
+ type: record[2],
143
+ notnull: (record[3] == 1),
144
+ dflt_value: record[4],
145
+ pk: (record[5] == 1) }
146
+ )
147
+ info.send(record[1] + "=", column_info)
148
+ end
149
+ info
150
+ end
151
+
152
+ private
153
+
154
+ def execute(sql)
155
+ self.class.execute(sql)
156
+ end
157
+
158
+ def self.execute(sql)
159
+ database = Facemock::Database.new
160
+ records = database.connection.execute sql
161
+ if records.empty? && sql =~ /^INSERT /
162
+ records = database.connection.execute <<-SQL
163
+ SELECT * FROM #{table_name} WHERE ROWID = last_insert_rowid();
164
+ SQL
165
+ end
166
+ database.disconnect!
167
+ records
168
+ end
169
+
170
+ def self.record_to_object(record)
171
+ return nil unless record
172
+ self.new(record_to_hash(record))
173
+ end
174
+
175
+ def self.records_to_objects(records)
176
+ records.inject([]) do |objects, record|
177
+ objects << record_to_object(record)
178
+ end
179
+ end
180
+
181
+ def record_to_hash(record)
182
+ self.class.record_to_hash(record)
183
+ end
184
+
185
+ # 以下の形式のHashが返される
186
+ # { id: x, ..., created_at: yyyy-mm-dd :hh:mm +xxxx }
187
+ def self.record_to_hash(record)
188
+ hash = Hashie::Mash.new
189
+ column_names.each_with_index do |column_name, index|
190
+ value = (record[index] == "") ? nil : record[index]
191
+ parsed_value = case column_type(column_name)
192
+ when "BOOLEAN" then eval(value)
193
+ when "DATETIME" then Time.parse(value)
194
+ else value
195
+ end
196
+ hash.send(column_name.to_s + "=", parsed_value)
197
+ end
198
+ hash
199
+ end
200
+
201
+ def self.define_find_method(method_name, column_name)
202
+ case method_name
203
+ when /^find_by_(.+)/ then define_find_by_column(column_name)
204
+ when /^find_all_by_(.+)/ then define_find_all_by_column(column_name)
205
+ else false
206
+ end
207
+ end
208
+
209
+ def self.define_find_by_column(column_name)
210
+ self.class_eval <<-EOF
211
+ def self.find_by_#{column_name}(value)
212
+ column_value = case value
213
+ when String then "'" + value + "'"
214
+ when Time then "'" + value.to_s + "'"
215
+ else value.to_s
216
+ end
217
+
218
+ sql = "SELECT * FROM #{table_name} WHERE #{column_name} = "
219
+ sql += column_value + " LIMIT 1;"
220
+ records = execute sql
221
+ record_to_object(records.first)
222
+ end
223
+ EOF
224
+ true
225
+ end
226
+
227
+ def self.define_find_all_by_column(column_name)
228
+ self.class_eval <<-EOF
229
+ def self.find_all_by_#{column_name}(value)
230
+ column_value = case value
231
+ when String then "'" + value + "'"
232
+ when Time then "'" + value.to_s + "'"
233
+ else value.to_s
234
+ end
235
+
236
+ sql = "SELECT * FROM #{table_name} WHERE #{column_name} = "
237
+ sql += column_value + ";"
238
+ records = execute sql
239
+ records_to_objects(records)
240
+ end
241
+ EOF
242
+ true
243
+ end
244
+
245
+ def define_column_getter(name)
246
+ self.class.class_eval <<-EOF
247
+ def #{name}
248
+ self.instance_variable_get(:@#{name})
249
+ end
250
+ EOF
251
+ end
252
+
253
+ def define_column_setter(name)
254
+ self.class.class_eval <<-EOF
255
+ def #{name}(value)
256
+ instance_variable_set(:@#{name.to_s.gsub("=", "")}, value)
257
+ end
258
+ EOF
259
+ end
260
+
261
+ # DatabaseへのINSERTが成功してからインスタンスのフィールド値を更新する
262
+ def insert!(options={})
263
+ opts = Hashie::Mash.new(options)
264
+ instance = self.class.new
265
+ column_names.each do |column_name|
266
+ if column_name != :created_at
267
+ if self.class.column_notnull(column_name) && column_is_empty?(column_name)
268
+ raise Facemock::Errors::ColumnTypeNotNull, "#{column_name} is null"
269
+ end
270
+ instance.send(column_name.to_s + "=", self.send(column_name))
271
+ if opts.send(column_name)
272
+ instance.send(column_name.to_s + "=", opts.send(column_name))
273
+ end
274
+ end
275
+ end
276
+
277
+ target_column_names = if instance.id
278
+ column_names
279
+ else
280
+ column_names.select{|name| name != :id}
281
+ end
282
+ instance.created_at = Time.now
283
+ target_column_values = target_column_names.inject([]) do |ary, column_name|
284
+ ary << "'#{instance.send(column_name)}'"
285
+ end
286
+ values = target_column_values.join(", ")
287
+ columns = target_column_names.join(', ')
288
+
289
+ sql = "INSERT INTO #{table_name}(#{columns}) VALUES ( #{values} );"
290
+ records = execute sql
291
+ set_attributes_from_record(records.first)
292
+ true
293
+ end
294
+
295
+ def update!(options={})
296
+ if options.empty?
297
+ column_names.each do |column_name|
298
+ if (value = self.send(column_name)) && column_name != :id
299
+ options[column_name] = value unless options.nil?
300
+ end
301
+ end
302
+ end
303
+
304
+ unless options.empty?
305
+ target_key_values = options.inject([]) do |ary, (key, value)|
306
+ ary << (value.kind_of?(Integer) ? "#{key} = #{value}" : "#{key} = '#{value}'")
307
+ end
308
+ sql = "UPDATE #{table_name} SET #{target_key_values.join(', ')} WHERE ID = #{self.id};"
309
+ execute sql
310
+ end
311
+ fetch
312
+ true
313
+ end
314
+
315
+ def set_attributes_from_record(record)
316
+ hash = record_to_hash(record)
317
+ column_names.each do |column_name|
318
+ method_name = column_name.to_s + "="
319
+ self.send(method_name, hash.send(column_name))
320
+ end
321
+ end
322
+
323
+ def column_is_empty?(column_name)
324
+ return true if self.send(column_name).nil?
325
+
326
+ return case self.class.column_type(column_name)
327
+ when "TEXT", "DATETIME", "BOOLEAN"
328
+ true if self.send(column_name) == ""
329
+ else
330
+ false
331
+ end
332
+ end
333
+
334
+ def self.column_notnull(column_name)
335
+ return nil unless column_names.include?(column_name.to_s.to_sym)
336
+ table_info.send(column_name).notnull
337
+ end
338
+ end
339
+ end
340
+ end
@@ -0,0 +1,26 @@
1
+ require 'facemock/database'
2
+ require 'facemock/database/table'
3
+ require 'sqlite3'
4
+ require 'hashie'
5
+
6
+ module Facemock
7
+ class Database
8
+ class User < Table
9
+ TABLE_NAME = :users
10
+ COLUMN_NAMES = [:id, :name, :email, :password, :installed, :access_token, :application_id, :created_at]
11
+
12
+ def initialize(options={})
13
+ opts = Hashie::Mash.new(options)
14
+ @id = (opts.id.to_i > 0) ? opts.id.to_i : ("10000" + (0..9).to_a.shuffle[0..10].join).to_i
15
+ @name = opts.name || rand(36**10).to_s(36)
16
+ @email = opts.email || name.gsub(" ", "_") + "@example.com"
17
+ @password = opts.password || rand(36**10).to_s(36)
18
+ @installed = opts.installed || false
19
+ @access_token = opts.access_token || Digest::SHA512.hexdigest(identifier.to_s)
20
+ app_id = opts.application_id.to_i
21
+ @application_id = (app_id > 0) ? app_id : nil
22
+ @created_at = opts.created_at
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,121 @@
1
+ require 'sqlite3'
2
+ require 'facemock/database/table'
3
+ require 'facemock/database/application'
4
+ require 'facemock/database/user'
5
+ require 'facemock/database/permission'
6
+
7
+ module Facemock
8
+ class Database
9
+ ADAPTER = "sqlite3"
10
+ DB_DIRECTORY = File.expand_path("../../../db", __FILE__)
11
+ DEFAULT_DB_NAME = "facemock"
12
+ TABLE_NAMES = [:applications, :users, :permissions]
13
+
14
+ attr_reader :name
15
+ attr_reader :connection
16
+
17
+ def initialize(name=nil)
18
+ @name = DEFAULT_DB_NAME
19
+ connect
20
+ create_tables
21
+ end
22
+
23
+ def connect
24
+ @connection = SQLite3::Database.new filepath
25
+ @state = :connected
26
+ @connection
27
+ end
28
+
29
+ def disconnect!
30
+ @connection.close
31
+ @state = :disconnected
32
+ nil
33
+ end
34
+
35
+ def connected?
36
+ @state == :connected
37
+ end
38
+
39
+ def drop
40
+ disconnect!
41
+ File.delete(filepath) if File.exist?(filepath)
42
+ nil
43
+ end
44
+
45
+ def clear
46
+ drop_tables
47
+ create_tables
48
+ end
49
+
50
+ def create_tables
51
+ TABLE_NAMES.each do |table_name|
52
+ self.send "create_#{table_name}_table" unless table_exists?(table_name)
53
+ end
54
+ true
55
+ end
56
+
57
+ def drop_table(table_name)
58
+ return false unless File.exist?(filepath) && table_exists?(table_name)
59
+ @connection.execute "drop table #{table_name};"
60
+ true
61
+ end
62
+
63
+ def drop_tables
64
+ return false unless File.exist?(filepath)
65
+ TABLE_NAMES.each{|table_name| drop_table(table_name) }
66
+ true
67
+ end
68
+
69
+ def filepath
70
+ name ||= @name
71
+ File.join(DB_DIRECTORY, "#{@name}.#{ADAPTER}")
72
+ end
73
+
74
+ def table_exists?(table_name)
75
+ tables = @connection.execute "select * from sqlite_master"
76
+ tables.each do |table|
77
+ return true if table[1].to_s == table_name.to_s
78
+ end
79
+ false
80
+ end
81
+
82
+ private
83
+
84
+ def create_applications_table
85
+ @connection.execute <<-SQL
86
+ CREATE TABLE applications (
87
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
88
+ secret TEXT NOT NULL,
89
+ created_at DATETIME NOT NULL,
90
+ UNIQUE(secret)
91
+ );
92
+ SQL
93
+ end
94
+
95
+ def create_users_table
96
+ @connection.execute <<-SQL
97
+ CREATE TABLE users (
98
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
99
+ name TEXT NOT NULL,
100
+ email TEXT NOT NULL,
101
+ password TEXT NOT NULL,
102
+ installed BOOLEAN NOT NULL,
103
+ access_token TEXT NOT NULL,
104
+ application_id INTEGER NOT NULL,
105
+ created_at DATETIME NOT NULL,
106
+ UNIQUE(access_token));
107
+ SQL
108
+ end
109
+
110
+ def create_permissions_table
111
+ @connection.execute <<-SQL
112
+ CREATE TABLE permissions (
113
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
114
+ name TEXT NOT NULL,
115
+ user_id INTEGER NOT NULL,
116
+ created_at DATETIME NOT NULL
117
+ );
118
+ SQL
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,7 @@
1
+ module Facemock
2
+ module Errors
3
+ class Error < StandardError; end
4
+ class IncorrectDataFormat < Error; end
5
+ class ColumnTypeNotNull < Error; end
6
+ end
7
+ end
@@ -0,0 +1,36 @@
1
+ require 'facemock/fb_graph/application/user'
2
+
3
+ module Facemock
4
+ module FbGraph
5
+ class Application
6
+ class TestUsers < Array
7
+ DEFAULT_LIMIT = 50
8
+ DEFAULT_AFTER = 0
9
+
10
+ def initialize(application_id, options={})
11
+ @limit = limit = (options[:limit] && options[:limit] > 0) ? options[:limit] : DEFAULT_LIMIT
12
+ @after = after = (options[:after] && options[:after] > 0) ? options[:after] : DEFAULT_AFTER
13
+ @application_id = application_id
14
+ st = after
15
+ ed = after + limit - 1
16
+ users = User.find_all_by_application_id(application_id).sort_by{|u| u.created_at}
17
+ users = users.reverse[st..ed] || []
18
+ super(users)
19
+ end
20
+
21
+ def collection
22
+ self
23
+ end
24
+
25
+ def next
26
+ options = { limit: @limit, after: @after + @limit }
27
+ TestUsers.new(@application_id, options)
28
+ end
29
+
30
+ def select
31
+ { limit: DEFAULT_LIMIT, after: DEFAULT_AFTER }
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,10 @@
1
+ module Facemock
2
+ module FbGraph
3
+ class Application
4
+ class User < Facemock::Database::User
5
+ class Permission < Facemock::Database::Permission
6
+ end
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,69 @@
1
+ require 'hashie'
2
+ require 'facemock/fb_graph/application/user/permission'
3
+
4
+ module Facemock
5
+ module FbGraph
6
+ class Application
7
+ class User < Facemock::Database::User
8
+ attr_reader :permission_objects
9
+
10
+ def initialize(options={})
11
+ opts = Hashie::Mash.new(options)
12
+ if opts.identifier
13
+ opts[:id] = opts.identifier
14
+ opts.delete(:identifier)
15
+ end
16
+ super(opts)
17
+
18
+ @permission_objects = User::Permission.find_all_by_user_id(self.id)
19
+ set_permissions(opts.permissions) if opts.permissions
20
+ end
21
+
22
+ def permissions
23
+ @permission_objects.inject([]) do |names, perm|
24
+ names << perm.name.to_sym
25
+ end
26
+ end
27
+
28
+ def save!
29
+ super
30
+ @permission_objects.each do |permission|
31
+ permission.save!
32
+ end
33
+ end
34
+
35
+ def fetch
36
+ @permission_objects = User::Permission.find_all_by_user_id(self.id)
37
+ super
38
+ end
39
+
40
+ def destroy
41
+ @permission_objects.each do |permission|
42
+ permission.destroy
43
+ end
44
+ super
45
+ end
46
+
47
+ def revoke!
48
+ @permission_objects.each do |permission|
49
+ permission.destroy
50
+ end
51
+ @permission_objects = []
52
+ end
53
+
54
+ private
55
+
56
+ def set_permissions(permissions_string)
57
+ permissions_string.gsub(/\s/, "").split(",").uniq.each do |permission_name|
58
+ unless @permission_objects.find{|perm| perm.name == permission_name}
59
+ @permission_objects << User::Permission.new(
60
+ name: permission_name,
61
+ user_id: self.id
62
+ )
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,48 @@
1
+ require 'hashie'
2
+ require 'facemock/config'
3
+ require 'facemock/fb_graph/application/user'
4
+ require 'facemock/fb_graph/application/test_users'
5
+ require 'facemock/database/application'
6
+
7
+ module Facemock
8
+ module FbGraph
9
+ class Application
10
+ attr_reader :identifier
11
+ attr_reader :secret
12
+
13
+ def initialize(identifier, options={})
14
+ opts = Hashie::Mash.new(options)
15
+ if (identifier == :app && opts.access_token)
16
+ identifier = (0..9).to_a.shuffle[0..15].join
17
+ secret = opts.access_token
18
+ else
19
+ secret = opts.secret || rand(36**32).to_s(36)
20
+ end
21
+
22
+ @record = Facemock::Database::Application.new({id: identifier, secret: secret})
23
+ @record.save! unless Facemock::Database::Application.find_by_id(identifier)
24
+ @identifier = identifier.to_i
25
+ @secret = secret
26
+ end
27
+
28
+ def fetch
29
+ if @record = Facemock::Database::Application.find_by_id(@identifier)
30
+ @identifier = @record.id
31
+ @secret = @record.secret
32
+ end
33
+ self
34
+ end
35
+
36
+ def test_user!(options={})
37
+ options.merge!({application_id: self.identifier})
38
+ user = User.new(options)
39
+ user.save!
40
+ user
41
+ end
42
+
43
+ def test_users(options={})
44
+ TestUsers.new(self.identifier, options)
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,13 @@
1
+ require 'facemock/fb_graph/application/user'
2
+
3
+ module Facemock
4
+ module FbGraph
5
+ module User
6
+ extend self
7
+
8
+ def me(access_token)
9
+ Application::User.find_by_access_token(access_token)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,30 @@
1
+ require 'fb_graph'
2
+ require 'facemock/config'
3
+ require 'facemock/fb_graph/user'
4
+ require 'facemock/fb_graph/application'
5
+
6
+ module Facemock
7
+ module FbGraph
8
+ extend self
9
+
10
+ def on(options={})
11
+ if ::FbGraph != Facemock::FbGraph
12
+ Object.const_set(:SourceFbGraph, ::FbGraph)
13
+ Object.send(:remove_const, :FbGraph) if Object.constants.include?(:FbGraph)
14
+ Object.const_set(:FbGraph, Facemock::FbGraph)
15
+ end
16
+ true
17
+ end
18
+
19
+ def off
20
+ if ::FbGraph == Facemock::FbGraph
21
+ Object.send(:remove_const, :FbGraph) if Object.constants.include?(:FbGraph)
22
+ Object.const_set(:FbGraph, ::SourceFbGraph)
23
+ Object.send(:remove_const, :SourceFbGraph) if Object.constants.include?(:FbGraph)
24
+ end
25
+ true
26
+ end
27
+
28
+ class InvalidToken < ::FbGraph::InvalidToken; end
29
+ end
30
+ end