active_mocker 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.travis.yml +6 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +7 -0
- data/active_mocker.gemspec +30 -0
- data/lib/active_mocker.rb +5 -0
- data/lib/active_mocker/active_record.rb +12 -0
- data/lib/active_mocker/active_record/relationships.rb +34 -0
- data/lib/active_mocker/active_record/schema.rb +81 -0
- data/lib/active_mocker/active_record/scope.rb +12 -0
- data/lib/active_mocker/base.rb +170 -0
- data/lib/active_mocker/field.rb +28 -0
- data/lib/active_mocker/model_reader.rb +63 -0
- data/lib/active_mocker/reparameterize.rb +21 -0
- data/lib/active_mocker/schema_reader.rb +46 -0
- data/lib/active_mocker/table.rb +22 -0
- data/lib/active_mocker/version.rb +3 -0
- data/lib/file_reader.rb +7 -0
- data/lib/string_reader.rb +9 -0
- data/spec/lib/active_mocker/active_record/schema_spec.rb +2721 -0
- data/spec/lib/active_mocker/base_spec.rb +220 -0
- data/spec/lib/active_mocker/model_reader_spec.rb +126 -0
- data/spec/lib/active_mocker/schema_reader_spec.rb +124 -0
- data/spec/lib/model.rb +28 -0
- data/spec/lib/person.rb +9 -0
- data/spec/lib/schema.rb +40 -0
- metadata +152 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a57ab19178452d40493f706844efc26d8381d0b1
|
4
|
+
data.tar.gz: 360196e9eccecb12fef06ca111e002bfdd1cb5a7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ff22e9d0e5bef978329f85385e6865dcce9803a10a703de790ce2682f7715efda58b017007a05b4ab4e0d3ac7d24a2fb9c6255d078d9a9e974ca04f0f3029f16
|
7
|
+
data.tar.gz: 6b94c9d8b9025619a45f8991cb7592a5c43dd44258822405726cbfcdffc4730eaddbd94687e02842cb5ed219c7f08d8136ad501dd771820c30748f6aa5e61c7e
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Dustin Zeisler
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# ActiveMocker
|
2
|
+
[](https://travis-ci.org/zeisler/active_mocker)
|
3
|
+
Create mocks from active record models without loading rails or running a datebase
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'active_mocker'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install active_mocker
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it ( http://github.com/<my-github-username>/active_mocker/fork )
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'active_mocker/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "active_mocker"
|
8
|
+
spec.version = ActiveMocker::VERSION
|
9
|
+
spec.authors = ["Dustin Zeisler"]
|
10
|
+
spec.email = ["dustin@zive.me"]
|
11
|
+
spec.summary = %q{Create mocks from active record models without loading rails or running a database}
|
12
|
+
spec.description = %q{Create mocks from active record models without loading rails or running a database. The Mocks methods have the same arguments as the AR model and if they change you get a error in your test.}
|
13
|
+
spec.homepage = "https://github.com/zeisler/active_mocker"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
22
|
+
spec.add_development_dependency "rake", "~>10.1"
|
23
|
+
spec.add_development_dependency "rspec", "~>2.14"
|
24
|
+
spec.add_development_dependency "i18n", "~>0.6"
|
25
|
+
spec.add_development_dependency "activesupport", "~>4.0"
|
26
|
+
|
27
|
+
#spec.add_development_dependency "debase", "~>0.0"
|
28
|
+
#spec.add_development_dependency "ruby-debug-ide", "~>0.4"
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
$:.unshift File.expand_path('../../', __FILE__)
|
2
|
+
require 'active_mocker/active_record/scope'
|
3
|
+
require 'active_mocker/active_record/relationships'
|
4
|
+
|
5
|
+
module ActiveMocker
|
6
|
+
module ActiveRecord
|
7
|
+
class Base
|
8
|
+
extend Scope
|
9
|
+
extend Relationships
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
module Relationships
|
4
|
+
|
5
|
+
def relationships
|
6
|
+
OpenStruct.new({has_many: @has_many ||= [],
|
7
|
+
has_one: @has_one ||= [],
|
8
|
+
belongs_to: @belongs_to ||= [],
|
9
|
+
has_and_belongs_to_many: @has_and_belongs_to_many ||= []})
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def has_many(*args)
|
15
|
+
@has_many ||= []
|
16
|
+
@has_many.push args
|
17
|
+
end
|
18
|
+
|
19
|
+
def has_one(*args)
|
20
|
+
@has_one ||= []
|
21
|
+
@has_one.push args
|
22
|
+
end
|
23
|
+
|
24
|
+
def belongs_to(*args)
|
25
|
+
@belongs_to ||= []
|
26
|
+
@belongs_to.push args
|
27
|
+
end
|
28
|
+
|
29
|
+
def has_and_belongs_to_many(*args)
|
30
|
+
@has_and_belongs_to_many ||= []
|
31
|
+
@has_and_belongs_to_many.push args
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module ActiveMocker
|
2
|
+
module ActiveRecord
|
3
|
+
|
4
|
+
class Schema
|
5
|
+
|
6
|
+
def self.define(version: version, &block)
|
7
|
+
search_result = search_cache(@table_search)
|
8
|
+
search_result unless search_result.nil?
|
9
|
+
schema = parse
|
10
|
+
schema.instance_eval(&block)
|
11
|
+
add_to_cache schema.tables.first
|
12
|
+
schema.tables.first
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.parse
|
16
|
+
SchemaParser.new(@table_search)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.add_to_cache(table)
|
20
|
+
@@tables_cache ||= []
|
21
|
+
@@tables_cache << table unless table.nil?
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.search_cache(table_name)
|
25
|
+
@@tables_cache ||= []
|
26
|
+
@@tables_cache.find do |h|
|
27
|
+
h.name == table_name
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.clear_cache
|
32
|
+
@@tables_cache = []
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.search(table_name)
|
36
|
+
@table_search = table_name
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
class SchemaParser
|
42
|
+
|
43
|
+
attr_reader :tables, :table_search
|
44
|
+
|
45
|
+
def initialize(table_search)
|
46
|
+
@table_search = table_search
|
47
|
+
@tables = []
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
def create_table(name, options={}, &block)
|
52
|
+
tables << ActiveMocker::Table.new(name, CreateTable.new.instance_eval(&block)) if name == table_search
|
53
|
+
end
|
54
|
+
|
55
|
+
def method_missing(meth, *args)
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class CreateTable
|
62
|
+
|
63
|
+
attr_reader :fields
|
64
|
+
|
65
|
+
def initialize
|
66
|
+
@fields = []
|
67
|
+
end
|
68
|
+
|
69
|
+
def method_missing(meth, *args)
|
70
|
+
base_field meth, args
|
71
|
+
end
|
72
|
+
|
73
|
+
def base_field(type, args)
|
74
|
+
fields << Field.new(name: args.shift, type: type, options: args)
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
|
@@ -0,0 +1,170 @@
|
|
1
|
+
module ActiveMocker
|
2
|
+
|
3
|
+
#TODO DRY up method creation
|
4
|
+
#TODO have instance variable array for instance method
|
5
|
+
#TODO have class variable array for class method
|
6
|
+
#TODO enable support for active_hash as base class
|
7
|
+
#TODO work on options interface
|
8
|
+
|
9
|
+
class Base
|
10
|
+
|
11
|
+
attr_reader :model_name,
|
12
|
+
:model_options,
|
13
|
+
:options_schema,
|
14
|
+
:mass_assignment,
|
15
|
+
:model_relationships,
|
16
|
+
:schema_attributes,
|
17
|
+
:model_methods
|
18
|
+
|
19
|
+
def initialize(options={})
|
20
|
+
@schema_attributes = options.fetch(:schema_attributes, true)
|
21
|
+
@model_relationships = options.fetch(:model_relationships, true)
|
22
|
+
@model_methods = options.fetch(:model_methods, true)
|
23
|
+
@mass_assignment = options.fetch(:mass_assignment, true)
|
24
|
+
@model_options = options[:model]
|
25
|
+
@options_schema = options[:schema]
|
26
|
+
end
|
27
|
+
|
28
|
+
def mock(model_name)
|
29
|
+
@model_name = model_name
|
30
|
+
mock_class
|
31
|
+
end
|
32
|
+
|
33
|
+
def model_definition
|
34
|
+
return @model_definition unless @model_definition.nil?
|
35
|
+
@model_definition = ModelReader.new(model_options).parse(model_file_name)
|
36
|
+
end
|
37
|
+
|
38
|
+
def model_file_name
|
39
|
+
model_name.tableize.singularize
|
40
|
+
end
|
41
|
+
|
42
|
+
def table_definition
|
43
|
+
table_name = model_name.tableize
|
44
|
+
table = SchemaReader.new(options_schema).search(table_name)
|
45
|
+
raise "#{table_name} table not found." if table.nil?
|
46
|
+
return table
|
47
|
+
end
|
48
|
+
|
49
|
+
def mock_class
|
50
|
+
add_method_mock_of
|
51
|
+
add_instance_methods if model_methods
|
52
|
+
add_mock_instance_method if model_methods
|
53
|
+
add_relationships if model_relationships
|
54
|
+
add_class_methods if model_methods
|
55
|
+
add_column_names_method if schema_attributes
|
56
|
+
add_table_attributes if schema_attributes
|
57
|
+
create_initializer if mass_assignment
|
58
|
+
return @klass
|
59
|
+
end
|
60
|
+
|
61
|
+
def create_initializer
|
62
|
+
klass = create_klass
|
63
|
+
klass.instance_eval do
|
64
|
+
define_method('initialize') do |options={}|
|
65
|
+
options.each {|method, value| send("#{method}=", value)}
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def add_relationships
|
71
|
+
klass = create_klass
|
72
|
+
model_definition.relationships.each do |m|
|
73
|
+
klass.instance_variable_set("@#{m}", nil)
|
74
|
+
klass.class_eval { attr_accessor m }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def add_method_mock_of
|
79
|
+
klass = create_klass
|
80
|
+
klass.class_variable_set(:@@model_name, model_name)
|
81
|
+
klass.instance_eval do
|
82
|
+
define_method(:mock_of) {klass.class_variable_get :@@model_name}
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def add_table_attributes
|
87
|
+
klass = create_klass
|
88
|
+
table_definition.column_names.each do |m|
|
89
|
+
klass.instance_variable_set("@#{m}", nil)
|
90
|
+
klass.class_eval { attr_accessor m }
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def add_instance_methods
|
95
|
+
klass = create_klass
|
96
|
+
model_definition.instance_methods_with_arguments.each do |method|
|
97
|
+
m = method.keys.first
|
98
|
+
params = Reparameterize.call(method.values.first)
|
99
|
+
params_pass = Reparameterize.call(method.values.first, true)
|
100
|
+
klass.instance_variable_set("@#{m}", eval_lambda(params, %Q[raise "##{m} is not Implemented for Class: #{klass.name}"]))
|
101
|
+
block = eval_lambda(params, %Q[ self.class.instance_variable_get("@#{m}").call(#{params_pass})])
|
102
|
+
klass.instance_eval do
|
103
|
+
define_method(m, block)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def eval_lambda(arguments, block)
|
109
|
+
eval(%Q[ ->(#{arguments}){ #{block} }])
|
110
|
+
end
|
111
|
+
|
112
|
+
def add_mock_instance_method
|
113
|
+
klass = create_klass
|
114
|
+
klass.singleton_class.class_eval do
|
115
|
+
define_method(:mock_instance_method) do |method, &block|
|
116
|
+
klass.instance_variable_set("@#{method.to_s}", block)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def add_class_methods
|
122
|
+
klass = create_klass
|
123
|
+
model_definition.class_methods.each do |m|
|
124
|
+
klass.singleton_class.class_eval do
|
125
|
+
define_method(m) do
|
126
|
+
raise "::#{m} is not Implemented for Class: #{klass.name}"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def add_column_names_method
|
133
|
+
klass = create_klass
|
134
|
+
table = table_definition
|
135
|
+
klass.singleton_class.class_eval do
|
136
|
+
define_method(:column_names) do
|
137
|
+
table.column_names
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def create_klass
|
143
|
+
@klass ||= const_class
|
144
|
+
end
|
145
|
+
|
146
|
+
def const_class
|
147
|
+
remove_const(mock_class_name) if class_exists? mock_class_name
|
148
|
+
return Object.const_set(mock_class_name, Class.new) unless Object.const_defined?(mock_class_name)
|
149
|
+
return Object.const_get(mock_class_name, false)
|
150
|
+
end
|
151
|
+
|
152
|
+
def remove_const(class_name)
|
153
|
+
Object.send(:remove_const, class_name)
|
154
|
+
end
|
155
|
+
|
156
|
+
def class_exists?(class_name)
|
157
|
+
klass = Module.const_get(class_name)
|
158
|
+
return klass.is_a?(Class)
|
159
|
+
rescue NameError
|
160
|
+
return false
|
161
|
+
end
|
162
|
+
|
163
|
+
def mock_class_name
|
164
|
+
"#{model_name}Mock"
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
170
|
+
|