custom-attributes 0.2.17 → 0.2.18

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/Gemfile CHANGED
@@ -1,8 +1,9 @@
1
1
  source :gemcutter
2
2
 
3
3
  # Rails 3.0
4
- gem 'rails', '3.0.0'
4
+ gem 'rails', '3.0.1'
5
5
  gem 'rspec', '2.0.0'
6
+ #gem 'validates_timeliness', '~> 3.0.0'
6
7
  gem 'sqlite3-ruby', :require => 'sqlite3'
7
8
  gem 'mysql'
8
9
  gem 'pg'
data/Gemfile.lock CHANGED
@@ -2,12 +2,12 @@ GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
4
  abstract (1.0.0)
5
- actionmailer (3.0.0)
6
- actionpack (= 3.0.0)
5
+ actionmailer (3.0.1)
6
+ actionpack (= 3.0.1)
7
7
  mail (~> 2.2.5)
8
- actionpack (3.0.0)
9
- activemodel (= 3.0.0)
10
- activesupport (= 3.0.0)
8
+ actionpack (3.0.1)
9
+ activemodel (= 3.0.1)
10
+ activesupport (= 3.0.1)
11
11
  builder (~> 2.1.2)
12
12
  erubis (~> 2.6.6)
13
13
  i18n (~> 0.4.1)
@@ -15,19 +15,19 @@ GEM
15
15
  rack-mount (~> 0.6.12)
16
16
  rack-test (~> 0.5.4)
17
17
  tzinfo (~> 0.3.23)
18
- activemodel (3.0.0)
19
- activesupport (= 3.0.0)
18
+ activemodel (3.0.1)
19
+ activesupport (= 3.0.1)
20
20
  builder (~> 2.1.2)
21
21
  i18n (~> 0.4.1)
22
- activerecord (3.0.0)
23
- activemodel (= 3.0.0)
24
- activesupport (= 3.0.0)
22
+ activerecord (3.0.1)
23
+ activemodel (= 3.0.1)
24
+ activesupport (= 3.0.1)
25
25
  arel (~> 1.0.0)
26
26
  tzinfo (~> 0.3.23)
27
- activeresource (3.0.0)
28
- activemodel (= 3.0.0)
29
- activesupport (= 3.0.0)
30
- activesupport (3.0.0)
27
+ activeresource (3.0.1)
28
+ activemodel (= 3.0.1)
29
+ activesupport (= 3.0.1)
30
+ activesupport (3.0.1)
31
31
  arel (1.0.1)
32
32
  activesupport (~> 3.0.0)
33
33
  builder (2.1.2)
@@ -59,17 +59,17 @@ GEM
59
59
  rack (>= 1.0.0)
60
60
  rack-test (0.5.6)
61
61
  rack (>= 1.0)
62
- rails (3.0.0)
63
- actionmailer (= 3.0.0)
64
- actionpack (= 3.0.0)
65
- activerecord (= 3.0.0)
66
- activeresource (= 3.0.0)
67
- activesupport (= 3.0.0)
62
+ rails (3.0.1)
63
+ actionmailer (= 3.0.1)
64
+ actionpack (= 3.0.1)
65
+ activerecord (= 3.0.1)
66
+ activeresource (= 3.0.1)
67
+ activesupport (= 3.0.1)
68
68
  bundler (~> 1.0.0)
69
- railties (= 3.0.0)
70
- railties (3.0.0)
71
- actionpack (= 3.0.0)
72
- activesupport (= 3.0.0)
69
+ railties (= 3.0.1)
70
+ railties (3.0.1)
71
+ actionpack (= 3.0.1)
72
+ activesupport (= 3.0.1)
73
73
  rake (>= 0.8.4)
74
74
  thor (~> 0.14.0)
75
75
  rake (0.8.7)
@@ -100,7 +100,7 @@ DEPENDENCIES
100
100
  jeweler
101
101
  mysql
102
102
  pg
103
- rails (= 3.0.0)
103
+ rails (= 3.0.1)
104
104
  rcov
105
105
  rspec (= 2.0.0)
106
106
  sqlite3-ruby
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.17
1
+ 0.2.18
@@ -21,14 +21,19 @@ module ActiveRecord
21
21
  field_definitions = CustomAttributeDefinitionHelper.new field_types
22
22
  yield field_definitions if block_given?
23
23
  defined_custom_attributes = field_definitions.defined_attributes
24
+ defined_custom_validations = field_definitions.defined_validations
24
25
 
25
26
  if has_custom_attributes?
26
27
  write_inheritable_attribute(:defined_custom_attributes, self.defined_custom_attributes.deep_merge(defined_custom_attributes))
28
+ write_inheritable_attribute(:defined_custom_validations, self.defined_custom_validations.deep_merge(defined_custom_validations))
27
29
  write_inheritable_attribute(:defined_custom_field_types, field_types)
28
30
  else
29
31
  write_inheritable_attribute(:defined_custom_attributes, defined_custom_attributes)
30
32
  class_inheritable_reader(:defined_custom_attributes)
31
33
 
34
+ write_inheritable_attribute(:defined_custom_validations, defined_custom_validations)
35
+ class_inheritable_reader(:defined_custom_validations)
36
+
32
37
  write_inheritable_attribute(:defined_custom_field_types, extra_field_types)
33
38
  class_inheritable_reader(:defined_custom_field_types)
34
39
 
@@ -48,6 +53,7 @@ module ActiveRecord
48
53
 
49
54
  def initialize extra_field_types
50
55
  @defined_attributes = {}
56
+ @defined_validations = {}
51
57
 
52
58
  extra_field_types.each do |key, value|
53
59
  class_eval do
@@ -64,12 +70,14 @@ module ActiveRecord
64
70
  end
65
71
  end
66
72
 
67
- attr_reader :defined_attributes
73
+ attr_reader :defined_attributes, :defined_validations
68
74
 
69
75
  private
70
76
 
71
77
  def define_field(type, *args)
72
78
  options = args.extract_options!
79
+ options.assert_valid_keys(:on_model, :validate_with, :validate_all_with)
80
+
73
81
  attributes_on_model = {}
74
82
  if options[:on_model].is_a? Array
75
83
  options[:on_model].each do |attribute|
@@ -78,13 +86,18 @@ module ActiveRecord
78
86
  elsif options[:on_model].is_a? Hash
79
87
  attributes_on_model = options[:on_model]
80
88
  end
89
+ if options[:validate_all_with]
90
+ @defined_validations[type] = options[:validate_all_with]
91
+ end
92
+
81
93
  args.each do |field|
82
94
  field = field.to_sym
83
95
  @defined_attributes[type] ||= {}
84
96
  @defined_attributes[type][field] = {
85
97
  :type => type,
86
98
  :name => field,
87
- :on_model => attributes_on_model[field] || false
99
+ :on_model => attributes_on_model[field] || false,
100
+ :validate_with => options[:validate_with] || nil
88
101
  }
89
102
  end
90
103
  end
@@ -101,6 +114,7 @@ module ActiveRecord
101
114
 
102
115
  base.before_save :cache_custom_attributes
103
116
  base.after_save :save_custom_attributes
117
+ base.validate :validate_custom_attributes
104
118
  end
105
119
 
106
120
  module ClassMethods
@@ -126,6 +140,11 @@ module ActiveRecord
126
140
  def save_custom_attributes
127
141
  custom_attributes.save
128
142
  end
143
+
144
+ def validate_custom_attributes
145
+ custom_attributes.validate(errors)
146
+ end
147
+
129
148
  end
130
149
 
131
150
  end
@@ -5,6 +5,7 @@ class ActiveRecord::CustomAttributes::CustomAttribute
5
5
  @item_list = item_list
6
6
  @attribute_model = attribute_model
7
7
  @marked_for_destruction = false
8
+ @errors = ActiveModel::Errors.new(self)
8
9
  load if @attribute_model
9
10
  end
10
11
 
@@ -30,23 +31,34 @@ class ActiveRecord::CustomAttributes::CustomAttribute
30
31
  @marked_for_destruction
31
32
  end
32
33
 
33
- def save
34
- attribute_model.destroy and return if marked_for_destruction?
35
-
36
- attribute_model.value_type = type.to_s
37
- attribute_model.field_name = internal_label.to_s
38
- attribute_model.field_label = label
39
- write_value = item_list.supported_attribute_types[type]
40
- field = FIELD_MAPPING[write_value]
34
+ def validate
35
+ errors.clear
36
+ return if marked_for_destruction?
37
+ assign_model_value
38
+ unless attribute_model.valid?
39
+ attribute_model.errors.each do |attribute, message|
40
+ errors.add :value, message
41
+ end
42
+ end
43
+ validations = item_list.get_custom_validations_for type, internal_label
44
+ validations.each do |validator|
45
+ main_model.send(validator, self) if validator.is_a? Symbol
46
+ validator.call(self) if validator.is_a? Proc
47
+ end
48
+ end
41
49
 
42
- converted_value = value
43
- converted_value = value ? 1 : 0 if write_value == :boolean
50
+ def valid?
51
+ errors.empty?
52
+ end
44
53
 
45
- ([:text, :date_time, :number, :float] - [field]).each { |value_field| attribute_model.send("#{value_field}_value=", nil) }
46
- attribute_model.send("#{field}_value=", value)
54
+ def save
55
+ attribute_model.destroy and return if marked_for_destruction?
56
+ assign_model_value
47
57
  attribute_model.save
48
58
  end
49
59
 
60
+ attr_reader :errors
61
+
50
62
  private
51
63
 
52
64
  attr_reader :main_model, :item_list
@@ -62,6 +74,20 @@ class ActiveRecord::CustomAttributes::CustomAttribute
62
74
  :time => :date_time
63
75
  }
64
76
 
77
+ def assign_model_value
78
+ attribute_model.value_type = type.to_s
79
+ attribute_model.field_name = internal_label.to_s
80
+ attribute_model.field_label = label
81
+ write_value = item_list.supported_attribute_types[type]
82
+ field = FIELD_MAPPING[write_value]
83
+
84
+ converted_value = value
85
+ converted_value = value ? 1 : 0 if write_value == :boolean
86
+
87
+ ([:text, :date_time, :number, :float] - [field]).each { |value_field| attribute_model.send("#{value_field}_value=", nil) }
88
+ attribute_model.send("#{field}_value=", converted_value)
89
+ end
90
+
65
91
  def load
66
92
  self.type = attribute_model.value_type.to_sym
67
93
  self.internal_label = attribute_model.field_name.to_sym
@@ -1,8 +1,9 @@
1
1
  class ActiveRecord::CustomAttributes::CustomAttributeList
2
2
 
3
3
  def initialize(record)
4
- @record = record
5
- @defined_attributes = @record.class.defined_custom_attributes
4
+ @record = record
5
+ @defined_attributes = @record.class.defined_custom_attributes
6
+ @defined_validations = @record.class.defined_custom_validations
6
7
  @extra_attribute_types = @record.class.defined_custom_field_types
7
8
  define_attribute_methods
8
9
  end
@@ -21,10 +22,10 @@ class ActiveRecord::CustomAttributes::CustomAttributeList
21
22
  end
22
23
 
23
24
  def add(type, label, value)
24
- type = type.to_sym
25
+ type = type.to_sym
25
26
  return if label.blank? and value.respond_to? :blank? and value.blank?
26
- internal_label = convert_to_internal_label(type, label)
27
- attribute = get_attribute(type, internal_label || label, true)
27
+ internal_label = convert_to_internal_label(type, label)
28
+ attribute = get_attribute(type, internal_label || label, true)
28
29
  attribute.value = value
29
30
  end
30
31
 
@@ -46,6 +47,21 @@ class ActiveRecord::CustomAttributes::CustomAttributeList
46
47
  loaded_attributes.each(&:save)
47
48
  end
48
49
 
50
+ def validate(errors)
51
+ loaded_attributes.each do |a|
52
+ a.validate
53
+ unless a.valid?
54
+ a.errors.each do |attribute, error_message|
55
+ errors.add(:custom_attributes, error_message)
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+ def get_custom_validations_for(type, name)
62
+ [defined_validations[type], defined_attributes[type][name][:validate_with]].compact
63
+ end
64
+
49
65
  def defined_attribute_types
50
66
  (extra_attribute_types.keys + defined_attributes.keys).uniq
51
67
  end
@@ -60,14 +76,14 @@ class ActiveRecord::CustomAttributes::CustomAttributeList
60
76
 
61
77
  def supported_attribute_types
62
78
  return @supported_attribute_types if @supported_attribute_types
63
- standard_attribute_types = {}
79
+ standard_attribute_types = {}
64
80
  ActiveRecord::CustomAttributes::CUSTOM_ATTRIBUTE_TYPES.each { |t| standard_attribute_types[t.to_sym] = t.to_sym }
65
81
  @supported_attribute_types = (standard_attribute_types.merge extra_attribute_types)
66
82
  end
67
83
 
68
84
  def rename_label_of attribute, new_name
69
- internal_label = convert_to_internal_label(attribute.type, new_name)
70
- attribute.label = new_name
85
+ internal_label = convert_to_internal_label(attribute.type, new_name)
86
+ attribute.label = new_name
71
87
  attribute.internal_label = internal_label
72
88
  end
73
89
 
@@ -77,26 +93,26 @@ class ActiveRecord::CustomAttributes::CustomAttributeList
77
93
 
78
94
  private
79
95
 
80
- attr_reader :defined_attributes, :extra_attribute_types, :record
96
+ attr_reader :defined_attributes, :extra_attribute_types, :defined_validations, :record
81
97
 
82
98
  def get_attribute(type, internal_label, auto_create = false)
83
99
  if internal_label.is_a? Symbol
84
- attribute = loaded_attributes.find { |a| a.type == type and a.internal_label.to_s == internal_label.to_s }
100
+ attribute = loaded_attributes.find { |a| a.type == type and a.internal_label.to_s == internal_label.to_s }
85
101
  else
86
102
  attribute = loaded_attributes.find { |a| a.type == type and a.label == internal_label }
87
103
  end
88
104
  return attribute if attribute
89
105
  return nil unless auto_create
90
106
 
91
- new_attribute = ActiveRecord::CustomAttributes::CustomAttribute.new(self, record, nil)
107
+ new_attribute = ActiveRecord::CustomAttributes::CustomAttribute.new(self, record, nil)
92
108
  new_attribute.type = type.to_sym
93
109
 
94
110
  if internal_label.is_a? Symbol
95
111
  new_attribute.internal_label = internal_label
96
- new_attribute.label = human_label_for(type, internal_label)
112
+ new_attribute.label = human_label_for(type, internal_label)
97
113
  else
98
114
  new_attribute.internal_label = convert_to_internal_label(type, internal_label)
99
- new_attribute.label = internal_label
115
+ new_attribute.label = internal_label
100
116
  end
101
117
 
102
118
  loaded_attributes << new_attribute
@@ -112,7 +128,7 @@ class ActiveRecord::CustomAttributes::CustomAttributeList
112
128
 
113
129
  def human_label_for(type, internal_name)
114
130
  translate_scope = [:activerecord, :custom_attributes, record.class.name.underscore.to_sym, type.to_sym]
115
- defaults = [internal_name.to_s.underscore.gsub("_", " ").capitalize]
131
+ defaults = [internal_name.to_s.underscore.gsub("_", " ").capitalize]
116
132
  I18n.t(internal_name, :scope => translate_scope, :default => defaults)
117
133
  end
118
134
 
@@ -2,4 +2,12 @@ class ActiveRecord::CustomAttributes::CustomAttributeModel < ActiveRecord::Base
2
2
  set_table_name "custom_attributes"
3
3
 
4
4
  belongs_to :item, :polymorphic => true
5
+ validates :date_time_value, :presence => { :if => :date_storage? }
6
+
7
+ private
8
+
9
+ def date_storage?
10
+ ["date_time", "date", "time"].include? value_type
11
+ end
12
+
5
13
  end
@@ -1,19 +1,13 @@
1
1
  require File.expand_path('../../spec_helper', __FILE__)
2
2
 
3
3
  describe "Model without custom attributes" do
4
-
5
4
  subject { Location }
6
-
7
5
  it { should_not have_custom_attributes }
8
-
9
6
  end
10
7
 
11
8
  describe "Model with custom attributes" do
12
-
13
9
  subject { Person }
14
-
15
10
  it { should have_custom_attributes }
16
-
17
11
  end
18
12
 
19
13
  describe "Custom attributes of a person" do
@@ -21,11 +15,12 @@ describe "Custom attributes of a person" do
21
15
  clean_database!
22
16
 
23
17
  I18n.backend.store_translations :'nl', {
24
- :activerecord => {:custom_attributes => {:person => {:telephone => {:private => "Prive"}}}}
18
+ :activerecord => {:custom_attributes => {:person => {:telephone => {:private => "Prive"}}}},
19
+ :date => {:formats => {:default => "%d-%m-%Y"}}
25
20
  }
26
21
  I18n.default_locale = 'nl'
27
22
 
28
- @person = Person.new
23
+ @person = Person.new
29
24
  end
30
25
 
31
26
  subject { @person.custom_attributes }
@@ -51,7 +46,7 @@ describe "Custom attributes of a person" do
51
46
  @person.save
52
47
 
53
48
  loaded_person = Person.find @person.id
54
- fields = loaded_person.custom_attributes.telephone_attributes
49
+ fields = loaded_person.custom_attributes.telephone_attributes
55
50
  fields.should have(1).item
56
51
  fields[0].value.should == "06 28 61 06 28"
57
52
  end
@@ -86,7 +81,7 @@ describe "Custom attributes of a person" do
86
81
  it "should mark attributes for deletion" do
87
82
  @person.custom_attributes.add_telephone "Prive", "06 28 61 06 28"
88
83
 
89
- fields = @person.custom_attributes.telephone_attributes
84
+ fields = @person.custom_attributes.telephone_attributes
90
85
  fields.should have(1).item
91
86
  fields[0].mark_for_destruction
92
87
 
@@ -100,7 +95,7 @@ describe "Custom attributes of a person" do
100
95
  it "should accept post data in an custom_attributes hash" do
101
96
  # field format is #{@object.class.model_name.underscore}[custom_attributes][#{attribute_type}][#{field_type}][]
102
97
 
103
- custom_attribute_post_data = {
98
+ custom_attribute_post_data = {
104
99
  "telephone" => {
105
100
  "0" => {
106
101
  "label" => "Prive",
@@ -111,7 +106,7 @@ describe "Custom attributes of a person" do
111
106
  "value" => "1234567890"
112
107
  }
113
108
  },
114
- "email" => {
109
+ "email" => {
115
110
  "0" => {
116
111
  "label" => "Prive",
117
112
  "value" => "matthijs.groen@gmail.com"
@@ -119,9 +114,9 @@ describe "Custom attributes of a person" do
119
114
  }
120
115
  }
121
116
 
122
- @person.custom_attributes = custom_attribute_post_data
117
+ @person.custom_attributes = custom_attribute_post_data
123
118
 
124
- fields = @person.custom_attributes.telephone_attributes
119
+ fields = @person.custom_attributes.telephone_attributes
125
120
  fields.should have(2).items
126
121
  fields[0].value.should == "06 28 61 06 28"
127
122
  fields[1].value.should == "1234567890"
@@ -130,31 +125,63 @@ describe "Custom attributes of a person" do
130
125
  custom_attribute_second_post_data = {
131
126
  "telephone" => {
132
127
  "0" => {
133
- "label" => "Prive",
134
- "value" => "06 28 61 06 28",
128
+ "label" => "Prive",
129
+ "value" => "06 28 61 06 28",
135
130
  "_destroy" => true
136
131
  },
137
132
  "1" => {
138
- "label" => "Werk",
139
- "value" => "1234567890",
133
+ "label" => "Werk",
134
+ "value" => "1234567890",
140
135
  "_destroy" => "false"
141
136
  }
142
137
  },
143
- "email" => {
138
+ "email" => {
144
139
  "0" => {
145
140
  "label" => "Prive",
146
141
  "value" => "matthijs.groen@gmail.com"
147
142
  }
148
143
  }
149
144
  }
150
- @person.custom_attributes = custom_attribute_second_post_data
145
+ @person.custom_attributes = custom_attribute_second_post_data
151
146
 
152
- fields = @person.custom_attributes.telephone_attributes
147
+ fields = @person.custom_attributes.telephone_attributes
153
148
  fields.should have(1).items
154
149
  fields[0].value.should == "1234567890"
155
150
 
156
151
  end
157
152
 
153
+ it "should invalidate incorrect values" do
154
+ custom_attribute_invalid_post_data = {
155
+ "date" => {
156
+ "0" => {
157
+ "label" => "Born on",
158
+ "value" => "23422stufferror"
159
+
160
+ }
161
+ }
162
+ }
163
+ @person.custom_attributes = custom_attribute_invalid_post_data
164
+ @person.should_not be_valid
165
+
166
+ date_attributes = @person.custom_attributes.date_attributes
167
+ date_attributes.should have(1).items
168
+ date_attributes[0].should_not be_valid
169
+ end
170
+
171
+ it "should validate correct values" do
172
+ custom_attribute_valid_post_data = {
173
+ "date" => {
174
+ "0" => {
175
+ "label" => "Born on",
176
+ "value" => "31-05-1981"
177
+
178
+ }
179
+ }
180
+ }
181
+ @person.custom_attributes = custom_attribute_valid_post_data
182
+ @person.should be_valid
183
+ end
184
+
158
185
  end
159
186
 
160
187
  describe "Custom attributes of a product" do
@@ -199,4 +226,19 @@ describe "Custom attributes of a product" do
199
226
  @product.custom_attributes.size_value_of(:width).should == nil
200
227
  end
201
228
 
229
+ it "should run custom validations as method" do
230
+ @product.custom_attributes.add_size "Width", 16.3 # too large
231
+ @product.should_not be_valid
232
+ end
233
+
234
+ it "should run custom validations as lambda (value incorrect)" do
235
+ @product.custom_attributes.add_date "In stock since", Date.civil(2009, 12, 31)
236
+ @product.should_not be_valid
237
+ end
238
+
239
+ it "should run custom validations as lambda (value correct)" do
240
+ @product.custom_attributes.add_date "In stock since", Date.civil(2010, 1, 1)
241
+ @product.should be_valid
242
+ end
243
+
202
244
  end
data/spec/models.rb CHANGED
@@ -3,7 +3,11 @@ class Person < ActiveRecord::Base
3
3
  has_custom_attributes :telephone => :string, :email => :string do |fields|
4
4
  fields.telephone :work, :private, :mobile, :fax
5
5
  fields.email :work, :private
6
- fields.date :born_on, :wed_on, :died_on, :on_model => [ :born_on ]
6
+ fields.date :born_on, :wed_on, :died_on, :on_model => [:born_on]
7
+ end
8
+
9
+ def attribute_email(errors)
10
+
7
11
  end
8
12
 
9
13
  end
@@ -14,7 +18,13 @@ class Product < ActiveRecord::Base
14
18
 
15
19
  has_custom_attributes :size => :float do |fields|
16
20
  fields.size :width, :height, :depth
17
- fields.url :details, :on_model => { :details => :details_url }
21
+ fields.size :validate_all_with => :attribute_size_validation
22
+ fields.url :details, :on_model => {:details => :details_url}
23
+ fields.date :in_stock_since, :validate_with => lambda { |attribute| attribute.errors.add(:value, "must be after 2010") if attribute.value.to_date.year < 2010 }
24
+ end
25
+
26
+ def attribute_size_validation(attribute)
27
+ attribute.errors.add(:value, "should be between 1 and 10") if attribute.value < 1 or attribute.value > 10
18
28
  end
19
29
 
20
30
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: custom-attributes
3
3
  version: !ruby/object:Gem::Version
4
- hash: 53
4
+ hash: 51
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 2
9
- - 17
10
- version: 0.2.17
9
+ - 18
10
+ version: 0.2.18
11
11
  platform: ruby
12
12
  authors:
13
13
  - Matthijs Groen
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-10-20 00:00:00 +02:00
18
+ date: 2010-10-27 00:00:00 +02:00
19
19
  default_executable:
20
20
  dependencies: []
21
21
 
@@ -45,6 +45,7 @@ files:
45
45
  - lib/generators/custom_attributes/migration/migration_generator.rb
46
46
  - lib/generators/custom_attributes/migration/templates/active_record/migration.rb
47
47
  - rails/init.rb
48
+ - spec/custom_attributes/custom_attributes.sqlite3
48
49
  - spec/custom_attributes/has_custom_attributes_spec.rb
49
50
  - spec/database.yml
50
51
  - spec/database.yml.sample