with_model 2.0.0 → 2.1.0
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 +5 -5
- data/.rubocop.yml +6 -0
- data/.travis.yml +22 -16
- data/Gemfile +11 -6
- data/LICENSE +1 -1
- data/README.md +11 -15
- data/Rakefile +20 -0
- data/bin/rake +18 -0
- data/lib/with_model.rb +4 -8
- data/lib/with_model/constant_stubber.rb +30 -8
- data/lib/with_model/methods.rb +2 -0
- data/lib/with_model/model.rb +7 -15
- data/lib/with_model/model/dsl.rb +10 -3
- data/lib/with_model/table.rb +3 -1
- data/lib/with_model/version.rb +3 -1
- data/spec/active_record_behaviors_spec.rb +27 -25
- data/spec/readme_spec.rb +23 -25
- data/spec/spec_helper.rb +13 -16
- data/spec/with_model_spec.rb +80 -68
- data/with_model.gemspec +14 -14
- metadata +27 -17
- data/Rakefile.rb +0 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 22f429a5cb8e986623de65004594810d642f7ca21b0bf24a0a1257defa40add9
|
4
|
+
data.tar.gz: a7a0cbbe47ba722b1359a438c18692a7927ff957c88cd0e0919ac3ab4ac65e92
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 63d816a1fe0782ee315073325b6eb59b468bc87c7899f3a124c181cc6542ee9c31d55768a3e2af8234ec6ffad9bb92037b012da5328128e835fce4a74d7a6b15
|
7
|
+
data.tar.gz: 6da66d3cbf860d19d5a2c661e01e75ff7aef341d78d64d12055d5c28ebc5e7401ea5c095b6b006da1c01bcb4b2100bf524681a63292ccf791cff7def6a987115
|
data/.rubocop.yml
ADDED
data/.travis.yml
CHANGED
@@ -2,36 +2,42 @@ language: ruby
|
|
2
2
|
sudo: false
|
3
3
|
|
4
4
|
rvm:
|
5
|
-
- "2.
|
6
|
-
- "2.
|
7
|
-
- "2.
|
8
|
-
- jruby-9.
|
5
|
+
- "2.5.1"
|
6
|
+
- "2.4.4"
|
7
|
+
- "2.3.7"
|
8
|
+
- jruby-9.2.0.0
|
9
9
|
|
10
10
|
install:
|
11
11
|
- bundle install --retry=3
|
12
12
|
|
13
13
|
env:
|
14
14
|
- ACTIVE_RECORD_BRANCH="master"
|
15
|
+
- ACTIVE_RECORD_BRANCH="5-2-stable"
|
16
|
+
- ACTIVE_RECORD_BRANCH="5-1-stable"
|
15
17
|
- ACTIVE_RECORD_BRANCH="5-0-stable"
|
16
|
-
-
|
18
|
+
- ACTIVE_RECORD_VERSION="~> 5.2.0"
|
19
|
+
- ACTIVE_RECORD_VERSION="~> 5.1.0"
|
17
20
|
- ACTIVE_RECORD_VERSION="~> 5.0.0"
|
18
21
|
- ACTIVE_RECORD_VERSION="~> 4.2.0"
|
19
22
|
|
20
23
|
matrix:
|
21
24
|
allow_failures:
|
22
25
|
- env: ACTIVE_RECORD_BRANCH="master"
|
26
|
+
- env: ACTIVE_RECORD_BRANCH="5-2-stable"
|
27
|
+
- env: ACTIVE_RECORD_BRANCH="5-1-stable"
|
23
28
|
- env: ACTIVE_RECORD_BRANCH="5-0-stable"
|
24
|
-
- env: ACTIVE_RECORD_BRANCH="4-2-stable"
|
25
29
|
exclude:
|
26
|
-
- rvm:
|
30
|
+
- rvm: 2.3.7
|
27
31
|
env: ACTIVE_RECORD_BRANCH="master"
|
28
|
-
- rvm:
|
29
|
-
env: ACTIVE_RECORD_BRANCH="5-0-stable"
|
30
|
-
- rvm: "2.1.10"
|
31
|
-
env: ACTIVE_RECORD_VERSION="~> 5.0.0"
|
32
|
-
- rvm: jruby-9.1.6.0
|
32
|
+
- rvm: jruby-9.2.0.0
|
33
33
|
env: ACTIVE_RECORD_BRANCH="master"
|
34
|
-
- rvm: jruby-9.
|
35
|
-
env: ACTIVE_RECORD_BRANCH="5-
|
36
|
-
- rvm: jruby-9.
|
37
|
-
env: ACTIVE_RECORD_VERSION="~> 5.
|
34
|
+
- rvm: jruby-9.2.0.0
|
35
|
+
env: ACTIVE_RECORD_BRANCH="5-2-stable"
|
36
|
+
- rvm: jruby-9.2.0.0
|
37
|
+
env: ACTIVE_RECORD_VERSION="~> 5.2.0"
|
38
|
+
- rvm: jruby-9.2.0.0
|
39
|
+
env: ACTIVE_RECORD_VERSION="~> 4.2.0"
|
40
|
+
|
41
|
+
addons:
|
42
|
+
code_climate:
|
43
|
+
repo_token: fe5c8a8b1b951a54707c08b6fb2a9a5edf9e0522d28bccc648454f774c9ccab1
|
data/Gemfile
CHANGED
@@ -1,12 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
source 'https://rubygems.org'
|
2
4
|
|
3
5
|
gemspec
|
4
6
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
7
|
+
gem 'lint-config-ruby', git: 'https://github.com/Casecommons/lint-config-ruby.git', tag: 'v1.0.0'
|
8
|
+
|
9
|
+
ar_branch = ENV['ACTIVE_RECORD_BRANCH']
|
10
|
+
ar_version = ENV['ACTIVE_RECORD_VERSION']
|
9
11
|
|
10
|
-
if
|
11
|
-
gem 'activerecord',
|
12
|
+
if ar_branch
|
13
|
+
gem 'activerecord', git: 'https://github.com/rails/rails.git', branch: ar_branch
|
14
|
+
gem 'arel', git: 'https://github.com/rails/arel.git' if ar_branch == 'master'
|
15
|
+
elsif ar_version
|
16
|
+
gem 'activerecord', ar_version # rubocop:disable Bundler/DuplicatedGem
|
12
17
|
end
|
data/LICENSE
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Copyright (c) 2010-
|
1
|
+
Copyright (c) 2010-2018 Case Commons, Inc. <http://casecommons.org>
|
2
2
|
|
3
3
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
4
|
of this software and associated documentation files (the "Software"), to deal
|
data/README.md
CHANGED
@@ -2,11 +2,13 @@
|
|
2
2
|
|
3
3
|
[](https://rubygems.org/gems/with_model)
|
4
4
|
[](https://travis-ci.org/Casecommons/with_model)
|
5
|
-
[](https://codeclimate.com/github/Casecommons/with_model)
|
6
|
-
[](https://coveralls.io/r/Casecommons/with_model)
|
7
5
|
|
8
6
|
`with_model` dynamically builds an ActiveRecord model (with table) before each test in a group and destroys it afterwards.
|
9
7
|
|
8
|
+
## Development status
|
9
|
+
|
10
|
+
`with_model` is actively maintained. It is quite stable, so while updates may appear infrequent, it is only because none are needed.
|
11
|
+
|
10
12
|
## Installation
|
11
13
|
|
12
14
|
Install as usual: `gem install with_model` or add `gem 'with_model'` to your Gemfile. See `.travis.yml` for supported (tested) Ruby versions.
|
@@ -43,24 +45,18 @@ After setting up as above, call `with_model` and inside its block pass it a `tab
|
|
43
45
|
require 'spec_helper'
|
44
46
|
|
45
47
|
describe "A blog post" do
|
46
|
-
|
47
|
-
module SomeModule; end
|
48
|
-
end
|
49
|
-
|
50
|
-
after :all do
|
51
|
-
Object.send :remove_const, :SomeModule
|
52
|
-
end
|
48
|
+
module MyModule; end
|
53
49
|
|
54
50
|
with_model :BlogPost do
|
55
|
-
# The table block
|
51
|
+
# The table block (and an options hash) is passed to ActiveRecord migration’s `create_table`.
|
56
52
|
table do |t|
|
57
53
|
t.string :title
|
58
54
|
t.timestamps null: false
|
59
55
|
end
|
60
56
|
|
61
|
-
# The model block
|
57
|
+
# The model block is the ActiveRecord model’s class body.
|
62
58
|
model do
|
63
|
-
include
|
59
|
+
include MyModule
|
64
60
|
has_many :comments
|
65
61
|
validates_presence_of :title
|
66
62
|
|
@@ -92,7 +88,7 @@ describe "A blog post" do
|
|
92
88
|
end
|
93
89
|
|
94
90
|
it "has the module" do
|
95
|
-
expect(BlogPost.include?(
|
91
|
+
expect(BlogPost.include?(MyModule)).to eq true
|
96
92
|
end
|
97
93
|
|
98
94
|
it "has the class method" do
|
@@ -171,9 +167,9 @@ end
|
|
171
167
|
|
172
168
|
## Versioning
|
173
169
|
|
174
|
-
|
170
|
+
`with_model` uses [Semantic Versioning 2.0.0](http://semver.org/spec/v2.0.0.html).
|
175
171
|
|
176
172
|
## License
|
177
173
|
|
178
|
-
Copyright © 2010–
|
174
|
+
Copyright © 2010–2018 [Case Commons, Inc](http://casecommons.org).
|
179
175
|
Licensed under the MIT license, see [LICENSE](/LICENSE) file.
|
data/Rakefile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
require 'rubocop/rake_task'
|
6
|
+
|
7
|
+
desc 'Run specs'
|
8
|
+
RSpec::Core::RakeTask.new
|
9
|
+
|
10
|
+
desc 'Run lint'
|
11
|
+
RuboCop::RakeTask.new
|
12
|
+
|
13
|
+
namespace 'doc' do
|
14
|
+
desc 'Generate README and preview in browser'
|
15
|
+
task 'readme' do
|
16
|
+
sh 'markdown README.md > README.html && open README.html'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
task default: %i[spec rubocop]
|
data/bin/rake
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'rake' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require 'pathname'
|
12
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
require 'rubygems'
|
16
|
+
require 'bundler/setup'
|
17
|
+
|
18
|
+
load Gem.bin_path('rake', 'rake')
|
data/lib/with_model.rb
CHANGED
@@ -1,13 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'with_model/model'
|
2
4
|
require 'with_model/model/dsl'
|
3
5
|
require 'with_model/table'
|
4
6
|
require 'with_model/version'
|
5
7
|
|
6
8
|
module WithModel
|
7
|
-
def with_model(name,
|
8
|
-
options = options.dup
|
9
|
-
scope = options.delete(:scope)
|
10
|
-
|
9
|
+
def with_model(name, scope: nil, **options, &block)
|
11
10
|
model = Model.new name, options
|
12
11
|
dsl = Model::DSL.new model
|
13
12
|
dsl.instance_exec(&block) if block
|
@@ -21,10 +20,7 @@ module WithModel
|
|
21
20
|
end
|
22
21
|
end
|
23
22
|
|
24
|
-
def with_table(name,
|
25
|
-
options = options.dup
|
26
|
-
scope = options.delete(:scope)
|
27
|
-
|
23
|
+
def with_table(name, scope: nil, **options, &block)
|
28
24
|
table = Table.new name, options, &block
|
29
25
|
|
30
26
|
before(*scope) do
|
@@ -1,24 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module WithModel
|
2
4
|
class ConstantStubber
|
3
|
-
def initialize
|
5
|
+
def initialize(const_name)
|
4
6
|
@const_name = const_name.to_sym
|
7
|
+
@namespace = nil
|
5
8
|
@original_value = nil
|
6
9
|
end
|
7
10
|
|
8
|
-
def stub_const
|
9
|
-
|
10
|
-
|
11
|
-
|
11
|
+
def stub_const(value)
|
12
|
+
@namespace = namespace
|
13
|
+
if @namespace.const_defined?(basename)
|
14
|
+
@original_value = @namespace.const_get(basename)
|
15
|
+
@namespace.__send__ :remove_const, basename
|
12
16
|
end
|
13
17
|
|
14
|
-
|
18
|
+
@namespace.const_set basename, value
|
15
19
|
end
|
16
20
|
|
17
21
|
def unstub_const
|
18
|
-
|
19
|
-
|
22
|
+
@namespace.__send__ :remove_const, basename
|
23
|
+
@namespace.const_set basename, @original_value if @original_value
|
24
|
+
@namespace = nil
|
20
25
|
@original_value = nil
|
21
26
|
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def namespace
|
31
|
+
*namespace_parts, _ = lookup_list
|
32
|
+
namespace_parts.reduce(Object) do |ns, ns_part|
|
33
|
+
ns.const_get(ns_part.to_sym)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def lookup_list
|
38
|
+
@const_name.to_s.split('::')
|
39
|
+
end
|
40
|
+
|
41
|
+
def basename
|
42
|
+
@basename ||= lookup_list.last
|
43
|
+
end
|
22
44
|
end
|
23
45
|
private_constant :ConstantStubber
|
24
46
|
end
|
data/lib/with_model/methods.rb
CHANGED
data/lib/with_model/model.rb
CHANGED
@@ -1,23 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_record'
|
2
4
|
require 'active_support/core_ext/string/inflections'
|
5
|
+
require 'English'
|
3
6
|
require 'with_model/constant_stubber'
|
4
7
|
require 'with_model/methods'
|
5
8
|
require 'with_model/table'
|
6
9
|
|
7
10
|
module WithModel
|
8
11
|
class Model
|
9
|
-
OPTIONS = [:superclass].freeze
|
10
|
-
private_constant :OPTIONS
|
11
|
-
|
12
12
|
attr_writer :model_block, :table_block, :table_options
|
13
13
|
|
14
|
-
def initialize
|
15
|
-
validate_options!(options)
|
14
|
+
def initialize(name, superclass: ActiveRecord::Base)
|
16
15
|
@name = name.to_sym
|
17
16
|
@model_block = nil
|
18
17
|
@table_block = nil
|
19
18
|
@table_options = {}
|
20
|
-
@superclass =
|
19
|
+
@superclass = superclass
|
21
20
|
end
|
22
21
|
|
23
22
|
def create
|
@@ -68,15 +67,8 @@ module WithModel
|
|
68
67
|
end
|
69
68
|
|
70
69
|
def table_name
|
71
|
-
uid = "
|
72
|
-
"with_model_#{@name.to_s.tableize}_#{uid}"
|
73
|
-
end
|
74
|
-
|
75
|
-
def validate_options!(options)
|
76
|
-
unknown_options = options.keys - OPTIONS
|
77
|
-
unless unknown_options.empty?
|
78
|
-
raise ArgumentError, "unknown options: #{unknown_options.inspect}"
|
79
|
-
end
|
70
|
+
uid = "#{$PID}_#{Thread.current.object_id}"
|
71
|
+
"with_model_#{@name.to_s.tableize}_#{uid}"
|
80
72
|
end
|
81
73
|
end
|
82
74
|
end
|
data/lib/with_model/model/dsl.rb
CHANGED
@@ -1,16 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module WithModel
|
2
4
|
class Model
|
3
5
|
class DSL
|
4
|
-
def initialize
|
6
|
+
def initialize(model)
|
5
7
|
@model = model
|
6
8
|
end
|
7
9
|
|
8
|
-
|
10
|
+
# Provide a schema definition for the table, passed to ActiveRecord’s `create_table`.
|
11
|
+
# The table name will be auto-generated.
|
12
|
+
#
|
13
|
+
# @see https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-create_table
|
14
|
+
def table(options = {}, &block)
|
9
15
|
@model.table_options = options
|
10
16
|
@model.table_block = block
|
11
17
|
end
|
12
18
|
|
13
|
-
|
19
|
+
# Provide a class body for the ActiveRecord model.
|
20
|
+
def model(&block)
|
14
21
|
@model.model_block = block
|
15
22
|
end
|
16
23
|
end
|
data/lib/with_model/table.rb
CHANGED
data/lib/with_model/version.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
3
|
-
describe
|
4
|
-
describe
|
5
|
-
context
|
5
|
+
describe 'ActiveRecord behaviors' do
|
6
|
+
describe 'a temporary ActiveRecord model created with with_model' do
|
7
|
+
context 'that has a named scope' do
|
6
8
|
before do
|
7
9
|
@regular_model = Class.new ActiveRecord::Base do
|
8
|
-
scope :title_is_foo,
|
10
|
+
scope :title_is_foo, -> { where(title: 'foo') }
|
9
11
|
end
|
10
12
|
|
11
13
|
@regular_model.connection.create_table(@regular_model.table_name, force: true) do |t|
|
@@ -27,39 +29,39 @@ describe "ActiveRecord behaviors" do
|
|
27
29
|
end
|
28
30
|
|
29
31
|
model do
|
30
|
-
scope :title_is_foo,
|
32
|
+
scope :title_is_foo, -> { where(title: 'foo') }
|
31
33
|
end
|
32
34
|
end
|
33
35
|
|
34
|
-
describe
|
35
|
-
it
|
36
|
-
included = @regular_model.create!(:
|
37
|
-
|
36
|
+
describe 'the named scope' do
|
37
|
+
it 'works like a regular named scope' do
|
38
|
+
included = @regular_model.create!(title: 'foo', content: 'Include me!')
|
39
|
+
@regular_model.create!(title: 'bar', content: 'Include me!')
|
38
40
|
|
39
41
|
expect(@regular_model.title_is_foo).to eq [included]
|
40
42
|
|
41
|
-
included = BlogPost.create!(:
|
42
|
-
|
43
|
+
included = BlogPost.create!(title: 'foo', content: 'Include me!')
|
44
|
+
BlogPost.create!(title: 'bar', content: 'Include me!')
|
43
45
|
|
44
46
|
expect(BlogPost.title_is_foo).to eq [included]
|
45
47
|
end
|
46
48
|
end
|
47
49
|
end
|
48
50
|
|
49
|
-
context
|
51
|
+
context 'that has a polymorphic belongs_to' do
|
50
52
|
before do
|
51
53
|
animal = Class.new ActiveRecord::Base do
|
52
|
-
has_many :tea_cups, :
|
54
|
+
has_many :tea_cups, as: :pet
|
53
55
|
end
|
54
56
|
stub_const 'Animal', animal
|
55
57
|
end
|
56
58
|
|
57
59
|
with_model :TeaCup do
|
58
60
|
table do |t|
|
59
|
-
t.belongs_to :pet, :
|
61
|
+
t.belongs_to :pet, polymorphic: true, index: false
|
60
62
|
end
|
61
63
|
model do
|
62
|
-
belongs_to :pet, :
|
64
|
+
belongs_to :pet, polymorphic: true
|
63
65
|
end
|
64
66
|
end
|
65
67
|
|
@@ -67,20 +69,20 @@ describe "ActiveRecord behaviors" do
|
|
67
69
|
|
68
70
|
with_model :StuffedAnimal do
|
69
71
|
model do
|
70
|
-
has_many :tea_cups, :
|
72
|
+
has_many :tea_cups, as: :pet
|
71
73
|
end
|
72
74
|
end
|
73
75
|
|
74
|
-
describe
|
75
|
-
it
|
76
|
+
describe 'the polymorphic belongs_to' do
|
77
|
+
it 'works like a regular polymorphic belongs_to' do
|
76
78
|
animal = Animal.create!
|
77
79
|
stuffed_animal = StuffedAnimal.create!
|
78
80
|
|
79
|
-
tea_cup_for_animal = TeaCup.create!(:
|
81
|
+
tea_cup_for_animal = TeaCup.create!(pet: animal)
|
80
82
|
expect(tea_cup_for_animal.pet_type).to eq 'Animal'
|
81
83
|
expect(animal.tea_cups).to include(tea_cup_for_animal)
|
82
84
|
|
83
|
-
tea_cup_for_stuffed_animal = TeaCup.create!(:
|
85
|
+
tea_cup_for_stuffed_animal = TeaCup.create!(pet: stuffed_animal)
|
84
86
|
expect(tea_cup_for_stuffed_animal.pet_type).to eq 'StuffedAnimal'
|
85
87
|
expect(stuffed_animal.tea_cups).to include(tea_cup_for_stuffed_animal)
|
86
88
|
end
|
@@ -88,7 +90,7 @@ describe "ActiveRecord behaviors" do
|
|
88
90
|
end
|
89
91
|
end
|
90
92
|
|
91
|
-
context
|
93
|
+
context 'with an association' do
|
92
94
|
with_model :Province do
|
93
95
|
table do |t|
|
94
96
|
t.belongs_to :country
|
@@ -100,13 +102,13 @@ describe "ActiveRecord behaviors" do
|
|
100
102
|
|
101
103
|
with_model :Country
|
102
104
|
|
103
|
-
context
|
104
|
-
it
|
105
|
-
Province.create!(:
|
105
|
+
context 'in earlier examples' do
|
106
|
+
it 'works as normal' do
|
107
|
+
Province.create!(country: Country.create!)
|
106
108
|
end
|
107
109
|
end
|
108
110
|
|
109
|
-
context
|
111
|
+
context 'in later examples' do
|
110
112
|
it "does not hold a reference to earlier example groups' classes" do
|
111
113
|
expect(Province.reflect_on_association(:country).klass).to eq Country
|
112
114
|
end
|