mockumentary 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +51 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +29 -0
- data/Rakefile +52 -0
- data/VERSION +1 -0
- data/lib/mockumentary/active_record.rb +23 -0
- data/lib/mockumentary/collection.rb +45 -0
- data/lib/mockumentary/data.rb +63 -0
- data/lib/mockumentary/mockery.rb +87 -0
- data/lib/mockumentary/mocksimile.rb +57 -0
- data/lib/mockumentary/model.rb +126 -0
- data/lib/mockumentary.rb +42 -0
- data/mockumentary.gemspec +92 -0
- data/spec/fixtures/app/models/event/follow.rb +3 -0
- data/spec/fixtures/app/models/event.rb +4 -0
- data/spec/fixtures/app/models/event_resource.rb +27 -0
- data/spec/fixtures/app/models/task.rb +2 -0
- data/spec/fixtures/app/models/user.rb +9 -0
- data/spec/fixtures/config/.gitkeep +0 -0
- data/spec/fixtures/db/schema.rb +33 -0
- data/spec/mockery/active_record_spec.rb +51 -0
- data/spec/mockery/collection_spec.rb +96 -0
- data/spec/mockery/data_spec.rb +15 -0
- data/spec/mockery/mockery_spec.rb +302 -0
- data/spec/mockery/mockumentary_spec.rb +24 -0
- data/spec/mockery/spec_helper.rb +31 -0
- data/spec/mocksimile/mocksimile_spec.rb +106 -0
- data/spec/mocksimile/mockumentary_spec.rb +38 -0
- data/spec/mocksimile/spec_helper.rb +18 -0
- metadata +182 -0
data/.document
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
gem "activesupport", ">= 2.3.5"
|
4
|
+
gem "hashie"
|
5
|
+
gem "faker"
|
6
|
+
|
7
|
+
group :development, :test do
|
8
|
+
gem 'activerecord', "~> 3.1.1", :require => 'active_record'
|
9
|
+
gem 'sqlite3'
|
10
|
+
gem "rspec", "~> 2.3.0"
|
11
|
+
gem "bundler", "~> 1.0.0"
|
12
|
+
gem "jeweler", "~> 1.6.4"
|
13
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
activemodel (3.1.1)
|
5
|
+
activesupport (= 3.1.1)
|
6
|
+
builder (~> 3.0.0)
|
7
|
+
i18n (~> 0.6)
|
8
|
+
activerecord (3.1.1)
|
9
|
+
activemodel (= 3.1.1)
|
10
|
+
activesupport (= 3.1.1)
|
11
|
+
arel (~> 2.2.1)
|
12
|
+
tzinfo (~> 0.3.29)
|
13
|
+
activesupport (3.1.1)
|
14
|
+
multi_json (~> 1.0)
|
15
|
+
arel (2.2.1)
|
16
|
+
builder (3.0.0)
|
17
|
+
diff-lcs (1.1.3)
|
18
|
+
faker (1.0.1)
|
19
|
+
i18n (~> 0.4)
|
20
|
+
git (1.2.5)
|
21
|
+
hashie (1.2.0)
|
22
|
+
i18n (0.6.0)
|
23
|
+
jeweler (1.6.4)
|
24
|
+
bundler (~> 1.0)
|
25
|
+
git (>= 1.2.5)
|
26
|
+
rake
|
27
|
+
multi_json (1.0.3)
|
28
|
+
rake (0.9.2.2)
|
29
|
+
rspec (2.3.0)
|
30
|
+
rspec-core (~> 2.3.0)
|
31
|
+
rspec-expectations (~> 2.3.0)
|
32
|
+
rspec-mocks (~> 2.3.0)
|
33
|
+
rspec-core (2.3.1)
|
34
|
+
rspec-expectations (2.3.0)
|
35
|
+
diff-lcs (~> 1.1.2)
|
36
|
+
rspec-mocks (2.3.0)
|
37
|
+
sqlite3 (1.3.4)
|
38
|
+
tzinfo (0.3.30)
|
39
|
+
|
40
|
+
PLATFORMS
|
41
|
+
ruby
|
42
|
+
|
43
|
+
DEPENDENCIES
|
44
|
+
activerecord (~> 3.1.1)
|
45
|
+
activesupport (>= 2.3.5)
|
46
|
+
bundler (~> 1.0.0)
|
47
|
+
faker
|
48
|
+
hashie
|
49
|
+
jeweler (~> 1.6.4)
|
50
|
+
rspec (~> 2.3.0)
|
51
|
+
sqlite3
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Kane Baccigalupi
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
= mockumentary
|
2
|
+
|
3
|
+
With the happy proliferation of TDD, test suites are getting massive, and developer efficiency is dwindling as we wait for our tests to pass. There is a big tradeoff between making unit test more integration-ish (and therefore more life-like) vs. making them very mocky, unity and fast. Mockumentary is a library for the
|
4
|
+
later. It inspects the ActiveRecord universe and makes a series of AR mockeries that approximate model without hitting the database, or making any assertions. The assertions, they are still part of the developers job in testing.
|
5
|
+
|
6
|
+
Mocumentary has two types of AR mock objects:
|
7
|
+
|
8
|
+
One is used within the Rails universe, a Mockery. It uses introspection to derive association and field information from its ActiveRecord class. It requires Rails or at least ActiveRecord in the test universe where it is used. These Mockeries can be dumped to YAML and used in an alternate universe of testing....
|
9
|
+
|
10
|
+
The second, a Mocksimile, is a non-introspective version built from a Mockery. In fact, Mockery dumps its class descriptions to a YAML file that is loaded by Mocksimile. This static version can be used outside the Rails test universe in a suite faster than the speed of Rails environment load time.
|
11
|
+
|
12
|
+
Mocking isn't for everyone, so test-drive responsibly.
|
13
|
+
|
14
|
+
|
15
|
+
== Contributing to mockumentary
|
16
|
+
|
17
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
18
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
19
|
+
* Fork the project
|
20
|
+
* Start a feature/bugfix branch
|
21
|
+
* Write test(s) (in Rspec and in the appropriate place) that describe the bug or feature
|
22
|
+
* Commit and push until you are happy with your contribution
|
23
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
24
|
+
|
25
|
+
== Copyright
|
26
|
+
|
27
|
+
Copyright (c) 2011 Kane Baccigalupi. See LICENSE.txt for
|
28
|
+
further details.
|
29
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
+
gem.name = "mockumentary"
|
18
|
+
gem.homepage = "http://github.com/baccigalupi/mockumentary"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = %Q{An ActiveRecord mocking framework, for making your copius BDD rails tests not quite so slow}
|
21
|
+
gem.description = <<-TEXT
|
22
|
+
With the happy proliferation of TDD, test suites are getting massive, and developer efficiency is dwindling
|
23
|
+
as we wait for our tests to pass. There is a big tradeoff between making unit test more integrationish (and therefore more reliable) vs.
|
24
|
+
making them very mocky, unity and fast. Mockumentary is a library for the later. It inspects the ActiveRecord universe and
|
25
|
+
makes a series of AR mockeries that approximate model without hitting the database, or making any assertions. The assertions,
|
26
|
+
they are still part of the developers job.
|
27
|
+
|
28
|
+
Mocumentary has two types of AR mockeries: One is used within the Rails universe. It uses introspection to derive association
|
29
|
+
and field information. The second is a static copy built from the first. This static version can be used outside the Rails
|
30
|
+
test universe in a suite faster than the speed of Rails environment load time.
|
31
|
+
|
32
|
+
Mocking isn't for everyone, so test-drive responsibly.
|
33
|
+
TEXT
|
34
|
+
gem.email = "baccigalupi@gmail.com"
|
35
|
+
gem.authors = ["Kane Baccigalupi"]
|
36
|
+
# dependencies defined in Gemfile
|
37
|
+
end
|
38
|
+
Jeweler::RubygemsDotOrgTasks.new
|
39
|
+
|
40
|
+
require 'rspec/core'
|
41
|
+
require 'rspec/core/rake_task'
|
42
|
+
RSpec::Core::RakeTask.new(:mockery) do |spec|
|
43
|
+
spec.pattern = FileList['spec/mockery/**/*_spec.rb']
|
44
|
+
end
|
45
|
+
|
46
|
+
RSpec::Core::RakeTask.new(:mocksimile) do |spec|
|
47
|
+
spec.pattern = FileList['spec/mocksimile/**/*_spec.rb']
|
48
|
+
end
|
49
|
+
|
50
|
+
desc "Run all specs"
|
51
|
+
task :spec => [:mockery, :mocksimile]
|
52
|
+
task :default => :spec
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.2.0
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Mockumentary
|
2
|
+
module ActiveRecord
|
3
|
+
def mock_class
|
4
|
+
@mock_class ||= discover_mock_class!
|
5
|
+
end
|
6
|
+
|
7
|
+
def discover_mock_class!
|
8
|
+
Mockery.classes.detect {|c| c.ar_class == self } || Mockery.generate(self)
|
9
|
+
end
|
10
|
+
|
11
|
+
def mock(opts={})
|
12
|
+
mock_class.mock(opts)
|
13
|
+
end
|
14
|
+
|
15
|
+
def mock!(opts={})
|
16
|
+
mock_class.mock!(opts)
|
17
|
+
end
|
18
|
+
|
19
|
+
def mew(opts={})
|
20
|
+
mock_class.new(opts)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Mockumentary
|
2
|
+
class Collection < Array
|
3
|
+
attr_accessor :type
|
4
|
+
|
5
|
+
def initialize(klass)
|
6
|
+
self.type = klass
|
7
|
+
end
|
8
|
+
|
9
|
+
def mock(i=1)
|
10
|
+
(1..i).each { self << type.mock }
|
11
|
+
self
|
12
|
+
end
|
13
|
+
|
14
|
+
def mock!(i=1)
|
15
|
+
(1..i).each { self << type.mock! }
|
16
|
+
self
|
17
|
+
end
|
18
|
+
|
19
|
+
def build(opts={})
|
20
|
+
self << type.new(opts)
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
def create(opts={})
|
25
|
+
self << type.new(opts).save
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
alias :create! :create
|
30
|
+
|
31
|
+
def delete(*args)
|
32
|
+
args.each {|e| super(e)}
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
36
|
+
alias :delete_all :clear
|
37
|
+
alias :destroy_all :clear
|
38
|
+
alias :reset :clear
|
39
|
+
|
40
|
+
def exist?(element)
|
41
|
+
map(&:id).include?(element.id)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Mockumentary
|
2
|
+
module Data
|
3
|
+
def self.generate(key)
|
4
|
+
self.send(key) if key.is_a?(Symbol) && respond_to?(key)
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.string
|
8
|
+
Faker::Lorem.words.join(' ')
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.text
|
12
|
+
Faker::Lorem.sentences.join(' ')
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.integer
|
16
|
+
rand(100)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.decimal
|
20
|
+
rand * 100
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.float
|
24
|
+
decimal
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.time
|
28
|
+
Time.now + rand(60) * (3600*24)
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.timestamp
|
32
|
+
time
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.datetime
|
36
|
+
time
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.date
|
40
|
+
Date.today + rand(60) * (3600*24)
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.binary
|
44
|
+
Faker::Lorem.characters
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.boolean
|
48
|
+
false
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.first_name
|
52
|
+
Faker::Name.first_name
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.last_name
|
56
|
+
Faker::Name.last_name
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.full_name
|
60
|
+
"#{first_name} #{last_name}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
class Mockery < Mockumentary::Model
|
2
|
+
def self.ar_class
|
3
|
+
@ar_class ||= infer_ar_class
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.ar_class=(klass)
|
7
|
+
@ar_class = klass
|
8
|
+
introspect if klass
|
9
|
+
klass
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.container_name
|
13
|
+
"Mockery"
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.infer_ar_class
|
17
|
+
self.to_s.gsub(/^#{container_name}/, '').constantize
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.build(klass)
|
21
|
+
super
|
22
|
+
class_eval "#{container_name}::#{klass}.ar_class = ::#{klass}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.reset_defaults
|
26
|
+
@relationships = nil
|
27
|
+
@save_defaults = nil
|
28
|
+
@mock_defaults = nil
|
29
|
+
@uid = nil
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.introspect
|
33
|
+
reset_defaults
|
34
|
+
|
35
|
+
# introspect columns
|
36
|
+
ar_class.columns.each do |c|
|
37
|
+
name = c.name.to_sym
|
38
|
+
if save_fields.include?(name)
|
39
|
+
save_defaults[name] = c.type if name != :id
|
40
|
+
else
|
41
|
+
mock_defaults[name] = c.type
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# introspect relationships
|
46
|
+
ar_class.reflections.each do |name, reflection|
|
47
|
+
attr_accessor name
|
48
|
+
class_name = reflection.options[:class_name] || name.to_s.classify
|
49
|
+
relationships[name] = lambda { Mockumentary::Collection.new(build(class_name)) } if reflection.collection?
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.dump dir = "#{Rails.root}/config"
|
54
|
+
File.open("#{dir}/#{DUMP_NAME}", 'w') do |f|
|
55
|
+
f.write(YAML.dump(data_dump))
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.data_dump
|
60
|
+
classes.inject({}) do |result, klass|
|
61
|
+
init = klass.init_defaults.dup
|
62
|
+
init.merge!(klass.overrides[:init]) if klass.overrides && klass.overrides[:init]
|
63
|
+
|
64
|
+
save = klass.save_defaults.dup
|
65
|
+
save.merge!(klass.overrides[:save]) if klass.overrides && klass.overrides[:save]
|
66
|
+
|
67
|
+
mock = klass.mock_defaults.dup
|
68
|
+
mock.merge!(klass.overrides[:mock]) if klass.overrides && klass.overrides[:mock]
|
69
|
+
|
70
|
+
relationships = klass.relationships.inject({}) do |result, array|
|
71
|
+
key = array.first
|
72
|
+
value = array.last # a lambda
|
73
|
+
relationship_type = value.call.type.to_s.gsub(/^Mockery::/, '')
|
74
|
+
result[key] = relationship_type
|
75
|
+
result
|
76
|
+
end
|
77
|
+
|
78
|
+
result[klass.ar_class.to_s] = {
|
79
|
+
:init => init,
|
80
|
+
:save => save,
|
81
|
+
:mock => mock,
|
82
|
+
:relationships => relationships
|
83
|
+
}
|
84
|
+
result
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
class Mocksimile < Mockumentary::Model
|
2
|
+
def self.generate(ar_class_name, opts=nil)
|
3
|
+
mock_class = super(ar_class_name)
|
4
|
+
mock_class.defaulterize(opts) if opts
|
5
|
+
mock_class
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.defaulterize(opts)
|
9
|
+
@init_defaults = opts[:init]
|
10
|
+
@mock_defaults = opts[:mock]
|
11
|
+
@save_defaults = opts[:save]
|
12
|
+
build_relationships(opts[:relationships])
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.build_relationships(opts)
|
16
|
+
attr_accessor *(opts.keys)
|
17
|
+
@relationships = opts.inject({}) do |result, arr|
|
18
|
+
key = arr.first
|
19
|
+
klass = generate( arr.last )
|
20
|
+
result[key] = lambda { Mockumentary::Collection.new(klass) }
|
21
|
+
|
22
|
+
result
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.container_name
|
27
|
+
"Mocksimile"
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.load(dir=nil)
|
31
|
+
unless dir
|
32
|
+
dir = if defined?(Rails)
|
33
|
+
Rails.root
|
34
|
+
elsif defined?(RAILS_ROOT)
|
35
|
+
RAILS_ROOT
|
36
|
+
else
|
37
|
+
''
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
path = "#{dir}/config/#{DUMP_NAME}"
|
42
|
+
unless File.exist?(path)
|
43
|
+
raise ArgumentError, "Could not find mockumentary.yml. Please include a path or define RAILS_ROOT"
|
44
|
+
end
|
45
|
+
config = YAML.load(File.read(path))
|
46
|
+
config.each{ |klass_name, options| Mocksimile.generate(klass_name, options) }
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.release
|
50
|
+
if self.to_s == container_name
|
51
|
+
classes.map{|c| c.release }
|
52
|
+
else
|
53
|
+
release_name = self.to_s.gsub(/^#{container_name}::/, '')
|
54
|
+
eval "::#{release_name} = #{self} unless defined?(::#{release_name})"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
module Mockumentary
|
2
|
+
class Model < Hashie::Mash
|
3
|
+
DUMP_NAME = 'mockumentary.yml'
|
4
|
+
|
5
|
+
def self.generate(klass)
|
6
|
+
mock_class = constantize klass
|
7
|
+
build klass unless mock_class
|
8
|
+
mock_class ||= constantize klass
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.init_defaults
|
12
|
+
@init_defaults ||= {
|
13
|
+
:new_record => true
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.mock_defaults
|
18
|
+
@mock_defaults ||= {}
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.save_defaults
|
22
|
+
@save_defaults ||= {
|
23
|
+
:new_record => false,
|
24
|
+
:id => :uid
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.classes
|
29
|
+
@classes ||= []
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.build(klass)
|
33
|
+
class_eval <<-RUBY
|
34
|
+
class #{container_name}::#{klass} < #{container_name}; end
|
35
|
+
classes << #{container_name}::#{klass}
|
36
|
+
RUBY
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.relationships
|
40
|
+
@relationships ||= {}
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.constantize(klass)
|
44
|
+
classes.detect{|c| c.to_s == "#{container_name}::#{klass}"}
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.uid
|
48
|
+
@uid ||= 0
|
49
|
+
@uid += 1
|
50
|
+
@uid
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.overrides
|
54
|
+
{}
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.fake_data(key)
|
58
|
+
data = Mockumentary::Data.generate(key)
|
59
|
+
|
60
|
+
unless data
|
61
|
+
data = if key == :uid
|
62
|
+
uid
|
63
|
+
elsif key.respond_to?(:call)
|
64
|
+
key.respond_to?(:call)
|
65
|
+
else
|
66
|
+
key
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
data
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.evaluate(opts)
|
74
|
+
opts.inject({}) do |result, arr|
|
75
|
+
result[arr.first] = fake_data(arr.last)
|
76
|
+
result
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.mock_opts
|
81
|
+
opts = init_defaults.dup
|
82
|
+
opts.merge!(mock_defaults)
|
83
|
+
opts.merge!(overrides[:mock]) if overrides && overrides[:mock]
|
84
|
+
evaluate(opts)
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.init_opts
|
88
|
+
opts = init_defaults.dup
|
89
|
+
opts.merge!(overrides[:init]) if overrides && overrides[:init]
|
90
|
+
evaluate(opts)
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.save_opts
|
94
|
+
opts = save_defaults.dup
|
95
|
+
opts.merge!(overrides[:save]) if overrides && overrides[:save]
|
96
|
+
evaluate(opts)
|
97
|
+
end
|
98
|
+
|
99
|
+
def initialize(opts={})
|
100
|
+
super(self.class.init_opts.merge(opts))
|
101
|
+
self.class.relationships.each do |key, value|
|
102
|
+
send("#{key}=", value.call)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.mock(opts={})
|
107
|
+
new(mock_opts.merge(opts))
|
108
|
+
end
|
109
|
+
|
110
|
+
def self.mock!(opts={})
|
111
|
+
instance = mock(opts)
|
112
|
+
instance.save(opts)
|
113
|
+
end
|
114
|
+
|
115
|
+
def save(opts={})
|
116
|
+
self.class.save_opts.merge(opts).each do |key, value|
|
117
|
+
self[key] = value
|
118
|
+
end
|
119
|
+
self
|
120
|
+
end
|
121
|
+
|
122
|
+
def self.save_fields
|
123
|
+
@save_fields ||= [:id, :created_at, :updated_at]
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
data/lib/mockumentary.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
Bundler.require
|
2
|
+
|
3
|
+
module Mockumentary
|
4
|
+
def self.introspect dir = "#{Rails.root}/app/models", namespace = ''
|
5
|
+
Dir.chdir(dir) do
|
6
|
+
Dir['*.rb'].each do |file|
|
7
|
+
require "#{dir}/#{file}"
|
8
|
+
ar_class = (namespace + file.gsub(/\.rb$/, '').classify).constantize
|
9
|
+
Mockery.generate(ar_class)
|
10
|
+
end
|
11
|
+
|
12
|
+
Dir['*'].each do |file|
|
13
|
+
path = "#{dir}/#{file}"
|
14
|
+
if File.directory?(path)
|
15
|
+
namespace << "::" unless namespace.empty?
|
16
|
+
namespace << "#{file.classify}::"
|
17
|
+
introspect(path, namespace)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.dump dir = "#{Rails.root}/config"
|
24
|
+
Mockery.dump
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.load(dir=nil)
|
28
|
+
Mocksimile.load(dir)
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.load_and_release(dir=nil)
|
32
|
+
load(dir)
|
33
|
+
Mocksimile.release
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
require 'mockumentary/data'
|
38
|
+
require 'mockumentary/collection'
|
39
|
+
require 'mockumentary/model'
|
40
|
+
require 'mockumentary/mockery'
|
41
|
+
require 'mockumentary/active_record'
|
42
|
+
require 'mockumentary/mocksimile'
|