data-attributes 0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/README.rdoc +73 -0
- data/Rakefile +7 -0
- data/data-attributes.gemspec +25 -0
- data/lib/data-attributes.rb +2 -0
- data/lib/data-attributes/data_attributes.rb +80 -0
- data/lib/data-attributes/errors.rb +10 -0
- data/lib/data-attributes/version.rb +3 -0
- data/test/data_attributes_test.rb +132 -0
- data/test/models.rb +26 -0
- data/test/schema.rb +30 -0
- data/test/test_helper.rb +9 -0
- metadata +104 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.rdoc
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
= Data Attributes
|
2
|
+
|
3
|
+
== Description
|
4
|
+
|
5
|
+
A gem for easy access to attributes stored in a serialized data hash.
|
6
|
+
|
7
|
+
== Summary
|
8
|
+
|
9
|
+
ActiveRecord attributes are mapped to columns in your database; however, many attributes that needed to be persisted for an object don't need their own column because they will never be searched or filtered on. One solution is to save these with a serialized hash into a text field in the database and provide similar access to the values as other attribute accessors.
|
10
|
+
|
11
|
+
== Usage
|
12
|
+
|
13
|
+
Consider a +User+ class that has a text field that is serialized, +:data+.
|
14
|
+
|
15
|
+
class User < ActiveRecord::Base
|
16
|
+
|
17
|
+
serialize :data
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
We can set an accessor to an attribute to be saved in the +:data+ field with the following:
|
22
|
+
|
23
|
+
data_attributes :details
|
24
|
+
|
25
|
+
This generates a read and write accessor called +details+.
|
26
|
+
|
27
|
+
u = User.new
|
28
|
+
u.details = "I don't need to query on this."
|
29
|
+
puts u.details
|
30
|
+
=> I don't need to query on this.
|
31
|
+
puts u.data.inspect
|
32
|
+
=> { "details" => "I don't need to query on this." }
|
33
|
+
|
34
|
+
The default serialized attribute used is +data+. There are two ways to change the serialized attribute used for storage. The first is set a different default attribute for the class.
|
35
|
+
|
36
|
+
data_attribute_column :more_data
|
37
|
+
|
38
|
+
This makes all of the accessors created with +data_attributes+ be saved in +more_data+ instead of +data+. If a class has two (or more) serialized attributes that will share the storage responsibilities, each attribute defined with +data_attributes+ can be individually assigned to a serialized attribute by using a hash.
|
39
|
+
|
40
|
+
data_attribute :details, { :serialized_column => :more_data }
|
41
|
+
|
42
|
+
This creates an accessor that saves +details+ to +more_data+.
|
43
|
+
|
44
|
+
You can set a default to be returned, in the case the value hasn't be set yet.
|
45
|
+
|
46
|
+
data_attribute :details, { :default => "default value" }
|
47
|
+
|
48
|
+
== Under The Hood
|
49
|
+
|
50
|
+
Like column accessors that make use of +read_attribute+ and +write_attribute+, +data-attributes+ uses +read_data_attribute+ and +write_data_attribute+ to access the serialized attribute. This allows the ability to overwrite an accessor so any validation or other data manipulation needed before the value is returned or saved.
|
51
|
+
|
52
|
+
== License
|
53
|
+
|
54
|
+
Copyright (c) 2011 Les Fletcher
|
55
|
+
|
56
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
57
|
+
a copy of this software and associated documentation files (the
|
58
|
+
"Software"), to deal in the Software without restriction, including
|
59
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
60
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
61
|
+
permit persons to whom the Software is furnished to do so, subject to
|
62
|
+
the following conditions:
|
63
|
+
|
64
|
+
The above copyright notice and this permission notice shall be
|
65
|
+
included in all copies or substantial portions of the Software.
|
66
|
+
|
67
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
68
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
69
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
70
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
71
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
72
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
73
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "data-attributes/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "data-attributes"
|
7
|
+
s.version = DataAttributes::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Les Fletcher"]
|
10
|
+
s.email = ["les.fletcher@gmail.com"]
|
11
|
+
s.homepage = ""
|
12
|
+
s.summary = %q{A gem for easy access to attributes stored in a serialized data hash}
|
13
|
+
s.description = %q{A gem for easy access to attributes stored in a serialized data hash}
|
14
|
+
|
15
|
+
s.rubyforge_project = "data-attributes"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_development_dependency('test-unit', '~> 2.2.0')
|
23
|
+
s.add_development_dependency('sqlite3', '~> 1.3.0')
|
24
|
+
s.add_dependency('activerecord', '~> 3.0.0')
|
25
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module DataAttributes
|
2
|
+
module DataAttributes
|
3
|
+
def self.included(base)
|
4
|
+
base.extend(ClassMethods)
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
DEFAULT_DATA_COLUMN = :data
|
9
|
+
|
10
|
+
# set the default serialized attribute to use to store all the values
|
11
|
+
# default is :data
|
12
|
+
# raises +NonSerializedColumnError+ if value isn't serlialized
|
13
|
+
def data_attribute_column(value)
|
14
|
+
raise(NonSerializedColumnError) unless serialized_attributes[value.to_s]
|
15
|
+
write_inheritable_attribute(:attr_data_attribute_column, value.to_sym)
|
16
|
+
end
|
17
|
+
|
18
|
+
# set up an attribute accessor for values stored in the serialized hash
|
19
|
+
# takes an attribute name and a hash sets up a read and write accessor for it
|
20
|
+
# options:
|
21
|
+
# :serialized_column => the column used to store the attribute info
|
22
|
+
# :default => what to return if the attribute is not set
|
23
|
+
# raises +NonSerializedColumnError+ if the column specified isn't serlialized
|
24
|
+
def data_attribute(name, arg_opts={})
|
25
|
+
opts = {
|
26
|
+
:serialized_column => attr_data_attribute_column,
|
27
|
+
:default => nil
|
28
|
+
}
|
29
|
+
|
30
|
+
opts.merge!(arg_opts)
|
31
|
+
|
32
|
+
# make sure the serialized_column is actually serialized
|
33
|
+
raise(NonSerializedColumnError) unless serialized_attributes[opts[:serialized_column].to_s]
|
34
|
+
|
35
|
+
attr_data_attributes[name.to_sym] = opts
|
36
|
+
|
37
|
+
attr_name = name.to_s
|
38
|
+
class_eval("def #{attr_name}; read_data_attribute('#{attr_name}'); end")
|
39
|
+
class_eval("def #{attr_name}= (value); write_data_attribute('#{attr_name}', value); end")
|
40
|
+
end
|
41
|
+
|
42
|
+
def attr_data_attributes
|
43
|
+
read_inheritable_attribute(:attr_data_attributes) or write_inheritable_attribute(:attr_data_attributes, {})
|
44
|
+
end
|
45
|
+
|
46
|
+
def attr_data_attribute_column
|
47
|
+
read_inheritable_attribute(:attr_data_attribute_column) or write_inheritable_attribute(:attr_data_attribute_column, DEFAULT_DATA_COLUMN)
|
48
|
+
end
|
49
|
+
|
50
|
+
def data_attribute_options(name)
|
51
|
+
attr_data_attributes.has_key?(name.to_sym) ? attr_data_attributes[name.to_sym] : raise(NonDataAttributeError)
|
52
|
+
end
|
53
|
+
|
54
|
+
def data_attribute_serialized_column(name)
|
55
|
+
data_attribute_options(name)[:serialized_column]
|
56
|
+
end
|
57
|
+
|
58
|
+
def data_attribute_default(name)
|
59
|
+
data_attribute_options(name)[:default]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def read_data_attribute(name)
|
64
|
+
(self.send(data_attribute_serialized_column(name)) || {}).has_key?(name) ? self.send(data_attribute_serialized_column(name))[name] : self.data_attribute_default(name)
|
65
|
+
end
|
66
|
+
|
67
|
+
def write_data_attribute(name, value)
|
68
|
+
if self.send(data_attribute_serialized_column(name)).nil?
|
69
|
+
self.send("#{data_attribute_serialized_column(name)}=", { name => value })
|
70
|
+
else
|
71
|
+
self.send("#{data_attribute_serialized_column(name)}=", self.send(data_attribute_serialized_column(name)).merge({ name => value }))
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def data_attribute_serialized_column(name); self.class.data_attribute_serialized_column(name) end
|
76
|
+
def data_attribute_default(name); self.class.data_attribute_default(name) end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
ActiveRecord::Base.send(:include, DataAttributes::DataAttributes)
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require File.expand_path( File.join( File.dirname( __FILE__ ), 'test_helper' ) )
|
2
|
+
|
3
|
+
class TestDataAttributes < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def test_setup
|
6
|
+
assert_equal Basic.attr_data_attribute_column, :data
|
7
|
+
assert_equal Basic.attr_data_attributes, { :stuff => { :serialized_column => :data, :default => nil } }
|
8
|
+
assert_equal TwoAttribute.attr_data_attribute_column, :data
|
9
|
+
assert_equal TwoAttribute.attr_data_attributes, {
|
10
|
+
:stuff => { :serialized_column => :data, :default => nil },
|
11
|
+
:things => { :serialized_column => :data, :default => nil }
|
12
|
+
}
|
13
|
+
assert_equal DifferentSerializedAttribute.attr_data_attribute_column, :more_data
|
14
|
+
assert_equal DifferentSerializedAttribute.attr_data_attributes, { :stuff => { :serialized_column => :more_data, :default => nil } }
|
15
|
+
assert_equal TwoSerializedAttribute.attr_data_attribute_column, :more_data
|
16
|
+
assert_equal TwoSerializedAttribute.attr_data_attributes, {
|
17
|
+
:stuff => { :serialized_column => :data, :default => 1 },
|
18
|
+
:things => { :serialized_column => :more_data, :default => "two" }
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_basic
|
23
|
+
b = Basic.new
|
24
|
+
assert_equal b.data, nil
|
25
|
+
assert_equal b.stuff, nil
|
26
|
+
|
27
|
+
b.stuff = "blah"
|
28
|
+
assert_equal b.stuff, "blah"
|
29
|
+
assert_equal b.data, { "stuff" => "blah" }
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_primitives_methods
|
33
|
+
b = Basic.new
|
34
|
+
assert_equal b.data, nil
|
35
|
+
assert_equal b.read_data_attribute("stuff"), nil
|
36
|
+
|
37
|
+
b.write_data_attribute("stuff", "blah")
|
38
|
+
assert_equal b.data, { "stuff" => "blah" }
|
39
|
+
assert_equal b.read_data_attribute("stuff"), "blah"
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_two_attributes
|
43
|
+
b = TwoAttribute.new
|
44
|
+
assert_equal b.data, nil
|
45
|
+
assert_equal b.stuff, nil
|
46
|
+
|
47
|
+
b.stuff = "blah"
|
48
|
+
assert_equal b.stuff, "blah"
|
49
|
+
assert_equal b.data, { "stuff" => "blah" }
|
50
|
+
|
51
|
+
b.things = "boom"
|
52
|
+
assert_equal b.stuff, "blah"
|
53
|
+
assert_equal b.things, "boom"
|
54
|
+
assert_equal b.data, { "stuff" => "blah", "things" => "boom" }
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_primitives_methods_two
|
58
|
+
b = TwoAttribute.new
|
59
|
+
assert_equal b.data, nil
|
60
|
+
assert_equal b.read_data_attribute("stuff"), nil
|
61
|
+
|
62
|
+
b.write_data_attribute("stuff", "blah")
|
63
|
+
assert_equal b.read_data_attribute("stuff"), "blah"
|
64
|
+
assert_equal b.data, { "stuff" => "blah" }
|
65
|
+
|
66
|
+
b.write_data_attribute("things", "boom")
|
67
|
+
assert_equal b.read_data_attribute("stuff"), "blah"
|
68
|
+
assert_equal b.read_data_attribute("things"), "boom"
|
69
|
+
assert_equal b.data, { "stuff" => "blah", "things" => "boom" }
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_two_serialized
|
73
|
+
t = TwoSerializedAttribute.new
|
74
|
+
assert_equal t.data, nil
|
75
|
+
assert_equal t.more_data, nil
|
76
|
+
assert_equal t.stuff, 1
|
77
|
+
assert_equal t.things, "two"
|
78
|
+
|
79
|
+
t.stuff = "stuff val"
|
80
|
+
t.things = "things val"
|
81
|
+
|
82
|
+
assert_equal t.stuff, "stuff val"
|
83
|
+
assert_equal t.things, "things val"
|
84
|
+
assert_equal t.more_data, { "things" => "things val" }
|
85
|
+
assert_equal t.data, { "stuff" => "stuff val" }
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_saving
|
89
|
+
b = Basic.create
|
90
|
+
id = b.id
|
91
|
+
assert_equal b.data, nil
|
92
|
+
assert_equal b.stuff, nil
|
93
|
+
|
94
|
+
b.stuff = "blah"
|
95
|
+
assert_equal b.stuff, "blah"
|
96
|
+
assert_equal b.data, { "stuff" => "blah" }
|
97
|
+
|
98
|
+
b.save
|
99
|
+
|
100
|
+
b = Basic.find(id)
|
101
|
+
assert_equal b.stuff, "blah"
|
102
|
+
assert_equal b.data, { "stuff" => "blah" }
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_non_serialized_error
|
106
|
+
klass = Class.new(ActiveRecord::Base)
|
107
|
+
ActiveRecord::Base.const_set("NonSerializedAttribute", klass)
|
108
|
+
|
109
|
+
assert_raise(DataAttributes::NonSerializedColumnError) do
|
110
|
+
klass.class_eval do
|
111
|
+
data_attribute :stuff
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_default_non_serialized_error
|
117
|
+
klass = Class.new(ActiveRecord::Base)
|
118
|
+
ActiveRecord::Base.const_set("DefaultNonSerializedAttribute", klass)
|
119
|
+
|
120
|
+
assert_raise(DataAttributes::NonSerializedColumnError) do
|
121
|
+
klass.class_eval do
|
122
|
+
data_attribute_column :more_data
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_data_attribute_options
|
128
|
+
assert_raise(DataAttributes::NonDataAttributeError) do
|
129
|
+
Basic.data_attribute_options(:things)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
data/test/models.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
class Basic < ActiveRecord::Base
|
2
|
+
serialize :data
|
3
|
+
data_attribute :stuff
|
4
|
+
end
|
5
|
+
|
6
|
+
class TwoAttribute < ActiveRecord::Base
|
7
|
+
serialize :data
|
8
|
+
data_attribute :stuff
|
9
|
+
data_attribute :things
|
10
|
+
end
|
11
|
+
|
12
|
+
class DifferentSerializedAttribute < ActiveRecord::Base
|
13
|
+
serialize :more_data
|
14
|
+
|
15
|
+
data_attribute_column :more_data
|
16
|
+
data_attribute :stuff
|
17
|
+
end
|
18
|
+
|
19
|
+
class TwoSerializedAttribute < ActiveRecord::Base
|
20
|
+
serialize :data
|
21
|
+
serialize :more_data
|
22
|
+
|
23
|
+
data_attribute_column :more_data
|
24
|
+
data_attribute :stuff, { :serialized_column => :data, :default => 1 }
|
25
|
+
data_attribute :things, { :default => "two" }
|
26
|
+
end
|
data/test/schema.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
ActiveRecord::Base.silence do
|
2
|
+
ActiveRecord::Migration.verbose = false
|
3
|
+
|
4
|
+
ActiveRecord::Schema.define do
|
5
|
+
create_table "basics" do |t|
|
6
|
+
t.text :data
|
7
|
+
end
|
8
|
+
|
9
|
+
create_table "two_attributes" do |t|
|
10
|
+
t.text :data
|
11
|
+
end
|
12
|
+
|
13
|
+
create_table "different_serialized_attribute" do |t|
|
14
|
+
t.text :more_data
|
15
|
+
end
|
16
|
+
|
17
|
+
create_table "two_serialized_attributes" do |t|
|
18
|
+
t.text :data
|
19
|
+
t.text :more_data
|
20
|
+
end
|
21
|
+
|
22
|
+
create_table "non_serialized_attributes" do |t|
|
23
|
+
t.text :data
|
24
|
+
end
|
25
|
+
|
26
|
+
create_table "default_non_serialized_attributes" do |t|
|
27
|
+
t.text :more_data
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'active_record'
|
3
|
+
|
4
|
+
require File.expand_path( File.join( File.dirname( __FILE__ ), '..', 'lib', 'data-attributes' ) )
|
5
|
+
|
6
|
+
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
|
7
|
+
|
8
|
+
require File.expand_path( File.join( File.dirname( __FILE__ ), 'schema' ) )
|
9
|
+
require File.expand_path( File.join( File.dirname( __FILE__ ), 'models' ) )
|
metadata
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: data-attributes
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: "0.2"
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Les Fletcher
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-04-10 00:00:00 -07:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: test-unit
|
18
|
+
prerelease: false
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
21
|
+
requirements:
|
22
|
+
- - ~>
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 2.2.0
|
25
|
+
type: :development
|
26
|
+
version_requirements: *id001
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: sqlite3
|
29
|
+
prerelease: false
|
30
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
31
|
+
none: false
|
32
|
+
requirements:
|
33
|
+
- - ~>
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: 1.3.0
|
36
|
+
type: :development
|
37
|
+
version_requirements: *id002
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: activerecord
|
40
|
+
prerelease: false
|
41
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ~>
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 3.0.0
|
47
|
+
type: :runtime
|
48
|
+
version_requirements: *id003
|
49
|
+
description: A gem for easy access to attributes stored in a serialized data hash
|
50
|
+
email:
|
51
|
+
- les.fletcher@gmail.com
|
52
|
+
executables: []
|
53
|
+
|
54
|
+
extensions: []
|
55
|
+
|
56
|
+
extra_rdoc_files: []
|
57
|
+
|
58
|
+
files:
|
59
|
+
- .gitignore
|
60
|
+
- Gemfile
|
61
|
+
- README.rdoc
|
62
|
+
- Rakefile
|
63
|
+
- data-attributes.gemspec
|
64
|
+
- lib/data-attributes.rb
|
65
|
+
- lib/data-attributes/data_attributes.rb
|
66
|
+
- lib/data-attributes/errors.rb
|
67
|
+
- lib/data-attributes/version.rb
|
68
|
+
- test/data_attributes_test.rb
|
69
|
+
- test/models.rb
|
70
|
+
- test/schema.rb
|
71
|
+
- test/test_helper.rb
|
72
|
+
has_rdoc: true
|
73
|
+
homepage: ""
|
74
|
+
licenses: []
|
75
|
+
|
76
|
+
post_install_message:
|
77
|
+
rdoc_options: []
|
78
|
+
|
79
|
+
require_paths:
|
80
|
+
- lib
|
81
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
82
|
+
none: false
|
83
|
+
requirements:
|
84
|
+
- - ">="
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: "0"
|
87
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
88
|
+
none: false
|
89
|
+
requirements:
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: "0"
|
93
|
+
requirements: []
|
94
|
+
|
95
|
+
rubyforge_project: data-attributes
|
96
|
+
rubygems_version: 1.5.0
|
97
|
+
signing_key:
|
98
|
+
specification_version: 3
|
99
|
+
summary: A gem for easy access to attributes stored in a serialized data hash
|
100
|
+
test_files:
|
101
|
+
- test/data_attributes_test.rb
|
102
|
+
- test/models.rb
|
103
|
+
- test/schema.rb
|
104
|
+
- test/test_helper.rb
|