loose_change 0.3.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.
- data/.gitignore +2 -0
- data/Gemfile +17 -0
- data/Gemfile.lock +41 -0
- data/LICENSE +20 -0
- data/README.md +39 -0
- data/Rakefile +31 -0
- data/VERSION +1 -0
- data/lib/loose_change.rb +23 -0
- data/lib/loose_change/attachments.rb +60 -0
- data/lib/loose_change/attributes.rb +79 -0
- data/lib/loose_change/base.rb +71 -0
- data/lib/loose_change/database.rb +52 -0
- data/lib/loose_change/errors.rb +7 -0
- data/lib/loose_change/helpers.rb +10 -0
- data/lib/loose_change/naming.rb +11 -0
- data/lib/loose_change/pagination.rb +69 -0
- data/lib/loose_change/persistence.rb +154 -0
- data/lib/loose_change/server.rb +11 -0
- data/lib/loose_change/views.rb +99 -0
- data/loose_change.gemspec +89 -0
- data/test/attachment_test.rb +22 -0
- data/test/attributes_test.rb +37 -0
- data/test/base_test.rb +22 -0
- data/test/callback_test.rb +35 -0
- data/test/inheritance_test.rb +36 -0
- data/test/pagination_test.rb +35 -0
- data/test/persistence_test.rb +126 -0
- data/test/resources/couchdb.png +0 -0
- data/test/test_helper.rb +12 -0
- data/test/view_test.rb +59 -0
- metadata +162 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
require './test/test_helper'
|
2
|
+
|
3
|
+
class AttachmentTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
setup do
|
6
|
+
class AttachmentModel < LooseChange::Base
|
7
|
+
use_database "test_db"
|
8
|
+
end
|
9
|
+
|
10
|
+
@model = AttachmentModel.new
|
11
|
+
end
|
12
|
+
|
13
|
+
should 'accept an attachment' do
|
14
|
+
@model.attach :photo, File.open(File.join(File.dirname(__FILE__), 'resources', 'couchdb.png')), :content_type => 'image/png'
|
15
|
+
assert @model.save
|
16
|
+
@retrieved = AttachmentModel.find(@model.id)
|
17
|
+
assert_equal({:photo => {:content_type => 'image/png'}}, @retrieved.attachments)
|
18
|
+
assert_not_nil @retrieved.attachment(:photo)
|
19
|
+
assert_equal @retrieved.attachment(:photo).size, @model.attachment(:photo).size
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require './test/test_helper'
|
2
|
+
|
3
|
+
class AttributesTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
setup do
|
6
|
+
class AttributesModel < LooseChange::Base
|
7
|
+
use_database "test_db"
|
8
|
+
|
9
|
+
property :age
|
10
|
+
property :name
|
11
|
+
validates_numericality_of :age
|
12
|
+
end
|
13
|
+
|
14
|
+
@model = AttributesModel.create
|
15
|
+
end
|
16
|
+
|
17
|
+
should 'allow attributes to updated' do
|
18
|
+
@model.update_attributes(:age => 1, :name => "John")
|
19
|
+
assert_equal 1, @model.age
|
20
|
+
assert_not_nil @model.id
|
21
|
+
end
|
22
|
+
|
23
|
+
should 'return false when attempting to update invalid attributes' do
|
24
|
+
assert_equal false, @model.update_attributes(:age => "John")
|
25
|
+
end
|
26
|
+
|
27
|
+
should 'allow update of one attribute' do
|
28
|
+
@model.update_attribute(:age, 10)
|
29
|
+
assert_equal 10, @model.age
|
30
|
+
assert_not_nil @model.id
|
31
|
+
end
|
32
|
+
|
33
|
+
should 'return false when attemping to update invalid attribute' do
|
34
|
+
assert_equal false, @model.update_attribute(:age, "Joe")
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
data/test/base_test.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require './test/test_helper'
|
2
|
+
|
3
|
+
class BaseTest < ActiveModel::TestCase
|
4
|
+
|
5
|
+
include ActiveModel::Lint::Tests
|
6
|
+
|
7
|
+
class CompliantModel < LooseChange::Base
|
8
|
+
use_database "test_db"
|
9
|
+
end
|
10
|
+
|
11
|
+
setup do
|
12
|
+
@model = CompliantModel.new
|
13
|
+
end
|
14
|
+
|
15
|
+
should 'be appropriately equal' do
|
16
|
+
@model.save
|
17
|
+
assert_equal @model, CompliantModel.find(@model.id)
|
18
|
+
assert_equal 1, ([@model] & [CompliantModel.find(@model.id)]).size
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require './test/test_helper'
|
2
|
+
|
3
|
+
class CallbackTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
class CallbackModel < LooseChange::Base
|
6
|
+
use_database "test_db"
|
7
|
+
property :name
|
8
|
+
property :age
|
9
|
+
before_save :double_age
|
10
|
+
after_destroy :create_copy
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def double_age() self.age = age * 2; end
|
15
|
+
def create_copy() CallbackModel.new(:age => age, :name => name).save; end
|
16
|
+
end
|
17
|
+
|
18
|
+
should 'run callback after destroy' do
|
19
|
+
d_model = CallbackModel.new(:age => 10, :name => 'd')
|
20
|
+
d_model.save
|
21
|
+
d_model.destroy
|
22
|
+
assert_equal d_model.name, CallbackModel.all.last.name
|
23
|
+
end
|
24
|
+
|
25
|
+
should 'run callback before save' do
|
26
|
+
model = CallbackModel.new(:age => 10, :name => 's')
|
27
|
+
model.save
|
28
|
+
retrieved = CallbackModel.find(model.id)
|
29
|
+
assert_equal 20, retrieved.age
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require './test/test_helper'
|
2
|
+
|
3
|
+
class InheritanceTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
setup do
|
6
|
+
class Parent < LooseChange::Base
|
7
|
+
use_database "test_db"
|
8
|
+
property :name
|
9
|
+
end
|
10
|
+
|
11
|
+
class Child < Parent
|
12
|
+
property :age
|
13
|
+
end
|
14
|
+
|
15
|
+
class AnotherChild < Parent
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
should "inherit the parent's database" do
|
21
|
+
assert_equal Child.new.database.name, Parent.new.database.name
|
22
|
+
end
|
23
|
+
|
24
|
+
should "not propagate its attributes back up the chain" do
|
25
|
+
p = Parent.new
|
26
|
+
assert_raise NoMethodError do
|
27
|
+
p.age = 2
|
28
|
+
end
|
29
|
+
|
30
|
+
c = AnotherChild.new
|
31
|
+
assert_raise NoMethodError do
|
32
|
+
c.age = 2
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require './test/test_helper'
|
2
|
+
|
3
|
+
class PaginationTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
setup do
|
6
|
+
class PaginationModel < LooseChange::Base
|
7
|
+
use_database "test_db"
|
8
|
+
property :age
|
9
|
+
property :height
|
10
|
+
|
11
|
+
paginated_view_by :age
|
12
|
+
paginated_view_by :age, :height
|
13
|
+
end
|
14
|
+
|
15
|
+
PaginationModel.all.each &:destroy
|
16
|
+
5.times { PaginationModel.create(:age => 10) }
|
17
|
+
5.times { PaginationModel.create(:age => 10, :height => 3) }
|
18
|
+
end
|
19
|
+
|
20
|
+
should 'automatically paginate all' do
|
21
|
+
assert_equal 4, PaginationModel.paginate(:page => 1, :per_page => 4).size
|
22
|
+
end
|
23
|
+
|
24
|
+
should 'paginate by properties' do
|
25
|
+
assert_equal 3, PaginationModel.paginated_by(:age, :key => 10, :page => 1, :per_page => 3).size
|
26
|
+
end
|
27
|
+
|
28
|
+
should 'paginate by multiple properties' do
|
29
|
+
assert_equal 1, PaginationModel.paginated_by('age_and_height', :key => [10, 3], :page => 2, :per_page => 4).size
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require './test/test_helper'
|
2
|
+
|
3
|
+
class PersistenceTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
setup do
|
6
|
+
LooseChange::Database.delete "test_db"
|
7
|
+
|
8
|
+
class TestModel < LooseChange::Base
|
9
|
+
use_database "test_db"
|
10
|
+
property :name, :default => "Jose"
|
11
|
+
property :age
|
12
|
+
timestamps!
|
13
|
+
end
|
14
|
+
|
15
|
+
@model = TestModel.new
|
16
|
+
@model.name = "Test"
|
17
|
+
end
|
18
|
+
|
19
|
+
should "not be persisted until saved" do
|
20
|
+
assert !@model.persisted?
|
21
|
+
end
|
22
|
+
|
23
|
+
should "be saveable" do
|
24
|
+
@model.save
|
25
|
+
assert @model.persisted?
|
26
|
+
assert_not_nil @model.id
|
27
|
+
end
|
28
|
+
|
29
|
+
should 'update its _rev on multiple saves' do
|
30
|
+
@model.save
|
31
|
+
assert_not_equal @model._rev, @model.save._rev
|
32
|
+
end
|
33
|
+
|
34
|
+
should "take save with a !" do
|
35
|
+
model = TestModel.new(:age => 2)
|
36
|
+
model.save!
|
37
|
+
assert model.persisted?
|
38
|
+
end
|
39
|
+
|
40
|
+
should "be createable" do
|
41
|
+
model = TestModel.create(:age => 2)
|
42
|
+
assert model.persisted?
|
43
|
+
assert_not_nil model.id
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'invalid models' do
|
47
|
+
class ValidationTestModel < LooseChange::Base
|
48
|
+
use_database "test_db"
|
49
|
+
property :name, :default => "Jose"
|
50
|
+
property :age
|
51
|
+
validates_numericality_of :age
|
52
|
+
timestamps!
|
53
|
+
end
|
54
|
+
|
55
|
+
should "not be saveable" do
|
56
|
+
@invalid_model = ValidationTestModel.new(:age => "Too old")
|
57
|
+
assert !(@invalid_model.save)
|
58
|
+
assert_raises LooseChange::RecordInvalid do
|
59
|
+
@invalid_model.save!
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
should "not be createable" do
|
64
|
+
assert !(ValidationTestModel.create(:age => "Too old").valid?)
|
65
|
+
assert ValidationTestModel.create(:age => "Too old").id.nil?
|
66
|
+
assert_raises LooseChange::RecordInvalid do
|
67
|
+
ValidationTestModel.create!(:age => "Too old")
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
should "not be saveable if no database set" do
|
73
|
+
class DBLessModel < LooseChange::Base
|
74
|
+
property :name
|
75
|
+
end
|
76
|
+
|
77
|
+
@invalid_model = DBLessModel.new(:name => "Problematic.")
|
78
|
+
assert_raises LooseChange::DatabaseNotSet do
|
79
|
+
@invalid_model.save
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
should "be gettable" do
|
84
|
+
@model.save
|
85
|
+
@retrieved = TestModel.find(@model.id)
|
86
|
+
assert_equal [@model.id, @model.name, @model.age], [@retrieved.id, @retrieved.name, @retrieved.age]
|
87
|
+
end
|
88
|
+
|
89
|
+
should "be saveable after get" do
|
90
|
+
@model.save
|
91
|
+
@model.age = 18
|
92
|
+
assert @model.save
|
93
|
+
@retrieved = TestModel.find(@model.id)
|
94
|
+
assert_equal [@model.id, @model.name, @model.age], [@retrieved.id, @retrieved.name, @retrieved.age]
|
95
|
+
end
|
96
|
+
|
97
|
+
should "be deletable" do
|
98
|
+
@model.save
|
99
|
+
@model.destroy
|
100
|
+
assert @model.destroyed?
|
101
|
+
assert_raise LooseChange::RecordNotFound do
|
102
|
+
TestModel.find(@model.id)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
should "honor a default" do
|
107
|
+
new_model = TestModel.new(:age => 2)
|
108
|
+
assert_equal "Jose", new_model.name
|
109
|
+
end
|
110
|
+
|
111
|
+
should "accept timestamps" do
|
112
|
+
time = Time.now
|
113
|
+
Timecop.travel(time)
|
114
|
+
new_model = TestModel.new
|
115
|
+
new_model.save
|
116
|
+
assert_times_close time, new_model.created_at
|
117
|
+
assert_times_close time, new_model.updated_at
|
118
|
+
future = time + 10.minutes
|
119
|
+
Timecop.travel(future)
|
120
|
+
new_model.save
|
121
|
+
assert_times_close future, new_model.updated_at
|
122
|
+
assert_times_close time, new_model.created_at
|
123
|
+
Timecop.return
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
Binary file
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'shoulda'
|
3
|
+
require 'active_model'
|
4
|
+
require './lib/loose_change'
|
5
|
+
require 'timecop'
|
6
|
+
|
7
|
+
# Thanks to Larry Marburger
|
8
|
+
module Test::Unit::Assertions
|
9
|
+
def assert_times_close(expected_time, actual_time, message = '')
|
10
|
+
assert_in_delta expected_time, actual_time, 0.01, message
|
11
|
+
end
|
12
|
+
end
|
data/test/view_test.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require './test/test_helper'
|
2
|
+
|
3
|
+
class ViewTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
setup do
|
6
|
+
LooseChange::Database.delete("test_db")
|
7
|
+
|
8
|
+
class ViewModel < LooseChange::Base
|
9
|
+
use_database "test_db"
|
10
|
+
property :name
|
11
|
+
property :age
|
12
|
+
|
13
|
+
view_by :name
|
14
|
+
view_by :name, :age
|
15
|
+
end
|
16
|
+
|
17
|
+
@model_one = ViewModel.new(:name => "Josh", :age => 20)
|
18
|
+
@model_two = ViewModel.new(:name => "John", :age => 20)
|
19
|
+
@model_one.save
|
20
|
+
@model_two.save
|
21
|
+
end
|
22
|
+
|
23
|
+
context "builtin views" do
|
24
|
+
should "be findable as all" do
|
25
|
+
assert_equal 2, ViewModel.all.size
|
26
|
+
end
|
27
|
+
|
28
|
+
should "be findable based on a view" do
|
29
|
+
result = ViewModel.by_name("Josh").first
|
30
|
+
assert_equal "Josh", result.name
|
31
|
+
end
|
32
|
+
|
33
|
+
should "be findable with multiple keys" do
|
34
|
+
results = ViewModel.by_name_and_age "Josh", 20
|
35
|
+
assert_equal 1, results.length
|
36
|
+
assert_equal "Josh", results.first.name
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "custom views" do
|
41
|
+
should "add a view" do
|
42
|
+
class ViewModel
|
43
|
+
add_view :double_age, "function(doc) { if ((doc['model_name'] == 'ViewTest::ViewModel') && (doc['age'] != null)) { emit(doc['age'] * 2, doc['age']); } }"
|
44
|
+
end
|
45
|
+
|
46
|
+
assert_equal 2, ViewModel.view(:double_age, :include_docs => false, :key => 40).size
|
47
|
+
assert_equal 20, ViewModel.view(:double_age, :include_docs => false, :key => 40).first
|
48
|
+
end
|
49
|
+
|
50
|
+
should "add a view with a reduce" do
|
51
|
+
class ViewModel
|
52
|
+
add_view :total_age, "function(doc) { if ((doc['model_name'] == 'ViewTest::ViewModel') && (doc['age'] != null)) { emit(null, doc['age']); } }", "function(key, reduce) { return sum(reduce); }"
|
53
|
+
end
|
54
|
+
assert_equal 40, ViewModel.view(:total_age, :include_docs => false, :group => true).first
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
metadata
ADDED
@@ -0,0 +1,162 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: loose_change
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 3
|
8
|
+
- 1
|
9
|
+
version: 0.3.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Joshua Miller
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-11-24 00:00:00 -05:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: activesupport
|
22
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
23
|
+
none: false
|
24
|
+
requirements:
|
25
|
+
- - ~>
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 3
|
29
|
+
- 0
|
30
|
+
- 0
|
31
|
+
version: 3.0.0
|
32
|
+
type: :runtime
|
33
|
+
prerelease: false
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: activemodel
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ~>
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
segments:
|
43
|
+
- 3
|
44
|
+
- 0
|
45
|
+
- 0
|
46
|
+
version: 3.0.0
|
47
|
+
type: :runtime
|
48
|
+
prerelease: false
|
49
|
+
version_requirements: *id002
|
50
|
+
- !ruby/object:Gem::Dependency
|
51
|
+
name: rest-client
|
52
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ~>
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
segments:
|
58
|
+
- 1
|
59
|
+
- 6
|
60
|
+
- 0
|
61
|
+
version: 1.6.0
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: *id003
|
65
|
+
- !ruby/object:Gem::Dependency
|
66
|
+
name: json
|
67
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
68
|
+
none: false
|
69
|
+
requirements:
|
70
|
+
- - ~>
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
segments:
|
73
|
+
- 1
|
74
|
+
- 4
|
75
|
+
- 6
|
76
|
+
version: 1.4.6
|
77
|
+
type: :runtime
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *id004
|
80
|
+
description:
|
81
|
+
email: josh@joshinharrisburg.com
|
82
|
+
executables: []
|
83
|
+
|
84
|
+
extensions: []
|
85
|
+
|
86
|
+
extra_rdoc_files:
|
87
|
+
- LICENSE
|
88
|
+
- README.md
|
89
|
+
files:
|
90
|
+
- .gitignore
|
91
|
+
- Gemfile
|
92
|
+
- Gemfile.lock
|
93
|
+
- LICENSE
|
94
|
+
- README.md
|
95
|
+
- Rakefile
|
96
|
+
- VERSION
|
97
|
+
- lib/loose_change.rb
|
98
|
+
- lib/loose_change/attachments.rb
|
99
|
+
- lib/loose_change/attributes.rb
|
100
|
+
- lib/loose_change/base.rb
|
101
|
+
- lib/loose_change/database.rb
|
102
|
+
- lib/loose_change/errors.rb
|
103
|
+
- lib/loose_change/helpers.rb
|
104
|
+
- lib/loose_change/naming.rb
|
105
|
+
- lib/loose_change/pagination.rb
|
106
|
+
- lib/loose_change/persistence.rb
|
107
|
+
- lib/loose_change/server.rb
|
108
|
+
- lib/loose_change/views.rb
|
109
|
+
- loose_change.gemspec
|
110
|
+
- test/attachment_test.rb
|
111
|
+
- test/attributes_test.rb
|
112
|
+
- test/base_test.rb
|
113
|
+
- test/callback_test.rb
|
114
|
+
- test/inheritance_test.rb
|
115
|
+
- test/pagination_test.rb
|
116
|
+
- test/persistence_test.rb
|
117
|
+
- test/resources/couchdb.png
|
118
|
+
- test/test_helper.rb
|
119
|
+
- test/view_test.rb
|
120
|
+
has_rdoc: true
|
121
|
+
homepage: http://github.com/joshuamiller/loose_change
|
122
|
+
licenses: []
|
123
|
+
|
124
|
+
post_install_message:
|
125
|
+
rdoc_options:
|
126
|
+
- --charset=UTF-8
|
127
|
+
require_paths:
|
128
|
+
- lib
|
129
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
130
|
+
none: false
|
131
|
+
requirements:
|
132
|
+
- - ">="
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
hash: 2553316803130877566
|
135
|
+
segments:
|
136
|
+
- 0
|
137
|
+
version: "0"
|
138
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
139
|
+
none: false
|
140
|
+
requirements:
|
141
|
+
- - ">="
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
segments:
|
144
|
+
- 0
|
145
|
+
version: "0"
|
146
|
+
requirements: []
|
147
|
+
|
148
|
+
rubyforge_project:
|
149
|
+
rubygems_version: 1.3.7
|
150
|
+
signing_key:
|
151
|
+
specification_version: 3
|
152
|
+
summary: ActiveModel-compliant CouchDB ORM
|
153
|
+
test_files:
|
154
|
+
- test/attachment_test.rb
|
155
|
+
- test/attributes_test.rb
|
156
|
+
- test/base_test.rb
|
157
|
+
- test/callback_test.rb
|
158
|
+
- test/inheritance_test.rb
|
159
|
+
- test/pagination_test.rb
|
160
|
+
- test/persistence_test.rb
|
161
|
+
- test/test_helper.rb
|
162
|
+
- test/view_test.rb
|