activeform-rails 0.0.2 → 0.0.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8e402d99e242dc5307a6bb925ec3d258ad6387b1
4
- data.tar.gz: bb2dd6443819e4363f684c26f8446266af5a655e
3
+ metadata.gz: 7f7688613c8527572ecc8edd552c918e6a45173a
4
+ data.tar.gz: 665ea65f9060f5b89b57dfdc65db238ea5c0cf08
5
5
  SHA512:
6
- metadata.gz: 28d4f5d2a1ea1431b1ea54202c6cb517d75b385291031809e43437ddf3ba783b46d66c5b022f5c74fe8d70281006f70bf4559e2858a97d07480b1d4ef0e785b3
7
- data.tar.gz: 13e22403ac71929269072c6914105bfbd29cb0173ee553bda95760c27d60269f47ef040ead1b855f531d0846eed897c6367e705514869f02a5ea8d75d961e7f2
6
+ metadata.gz: 190cf9b820a0ba65639caf4d71af7881ed907a51283c102f55899f94e0d27061979e9ea82c6f3c9b405a2ed121a77335c0bdd312f19b3a769f3bf5c48e60ce19
7
+ data.tar.gz: 02d4beba8aba2475ee300fb8c2547a428dddcb1fbc6d48010abd87418b3d231ac2a76558ae3663f31764b34a9ea25409dc4d213305b54ccb818f813fe1743c47
@@ -1,6 +1,9 @@
1
1
  module ActiveForm
2
+ class CannotBePersisted < Exception; end
2
3
  end
3
4
 
5
+ require 'active_support/core_ext/module/delegation'
4
6
  require 'active_record'
5
7
  require 'activeform-rails/form'
8
+ require 'activeform-rails/mock_model'
6
9
  require 'activeform-rails/validate_uniqueness'
@@ -8,15 +8,16 @@ module ActiveForm::Form
8
8
  base.extend ClassMethods
9
9
  end
10
10
 
11
-
12
11
  module ClassMethods
13
12
  delegate :model_name, :reflect_on_association, to: :main_class
14
13
  attr_accessor :main_class, :reflected_class, :main_model
15
14
 
16
- def properties(*attributes, prefix: false, on:)
17
- assign_delegators(attributes, on, prefix)
18
- add_model_on_list(on)
19
- add_accessor(on)
15
+ def properties(*attributes, prefix: false, on: nil)
16
+ if on.nil?
17
+ attr_accessor *attributes
18
+ else
19
+ delegate_to_model(attributes, on, prefix)
20
+ end
20
21
  end
21
22
 
22
23
  def i18n_scope
@@ -27,8 +28,21 @@ module ActiveForm::Form
27
28
  @models ||= []
28
29
  end
29
30
 
31
+ def main_model
32
+ @main_model ||= UnpersistentModel.new(self)
33
+ end
34
+
30
35
  def main_class
31
- @main_class ||= @main_model.to_s.camelize.constantize
36
+ @main_class ||= if main_model.kind_of?(Symbol)
37
+ main_model.to_s.camelize.constantize
38
+ else
39
+ @main_model
40
+ end
41
+ end
42
+
43
+ def alias_property(new_method, old_method)
44
+ alias_method new_method.to_sym, old_method.to_sym
45
+ alias_method "#{new_method}=".to_sym, "#{old_method}=".to_sym
32
46
  end
33
47
 
34
48
  private
@@ -47,11 +61,17 @@ module ActiveForm::Form
47
61
  delegate "#{attribute}=", to: model_name, prefix: prefix
48
62
  end
49
63
  end
64
+
65
+ def delegate_to_model(attributes, on, prefix)
66
+ assign_delegators(attributes, on, prefix)
67
+ add_model_on_list(on)
68
+ add_accessor(on)
69
+ end
50
70
  end
51
71
 
52
72
  delegate :to_key, :to_param, :id, :persisted?, to: :main_model
53
73
 
54
- def initialize(attributes)
74
+ def initialize(attributes = {})
55
75
  assign_from_hash(attributes)
56
76
  end
57
77
 
@@ -60,23 +80,40 @@ module ActiveForm::Form
60
80
  end
61
81
 
62
82
  def save(&block)
83
+ ensure_persistable
63
84
  valid?.tap do
64
85
  call_action_or_block(:save, &block)
65
86
  end
66
87
  end
67
88
 
68
89
  def save!(&block)
90
+ ensure_persistable
69
91
  ActiveRecord::Base.transaction do
70
92
  call_action_or_block(:save!, &block)
71
93
  end
72
94
  end
73
95
 
74
96
  def main_model
75
- send(self.class.main_model)
97
+ if self.class.main_model.kind_of?(Symbol)
98
+ send(self.class.main_model)
99
+ else
100
+ self.class.main_model
101
+ end
102
+ end
103
+
104
+ def new_record?
105
+ !persisted?
76
106
  end
77
107
 
78
108
  private
79
109
 
110
+ def ensure_persistable
111
+ message = 'The Form object is not backed by models so cannot be saved'
112
+ if self.class.models.empty?
113
+ raise ActiveForm::CannotBePersisted.new(message)
114
+ end
115
+ end
116
+
80
117
  def each_models
81
118
  self.class.models.each do |model_name|
82
119
  yield(send(model_name))
@@ -0,0 +1,24 @@
1
+ # UnpersistentModel allows the ActiveForm::Form object to delegate methods to
2
+ # this object with expected results
3
+ #
4
+ # - #model_name is used by Form helpers & Rails frequently to define the form namespace
5
+ # - #to_key, #to_param, #id should aways return nil as the Form cannot be persisted unless backed by ActiveModel
6
+ # - #persisted? should aways return false as the Form cannot be persisted unless backed by ActiveModel
7
+ #
8
+ module ActiveForm::Form
9
+ class UnpersistentModel
10
+ attr_reader :to_key, :to_param, :id
11
+
12
+ def initialize(base_klass)
13
+ @base_class = base_klass
14
+ end
15
+
16
+ def model_name
17
+ ActiveModel::Name.new(@base_class)
18
+ end
19
+
20
+ def persisted?
21
+ false
22
+ end
23
+ end
24
+ end
@@ -7,9 +7,9 @@ module ActiveForm
7
7
  end
8
8
 
9
9
  module ClassMethods
10
- def validates_uniqueness_of(attribute, model_name)
10
+ def validates_uniqueness_of(attribute, model_name, options = {})
11
11
  @attribute = attribute
12
- validates_each attribute do |form, attr, value|
12
+ validates_each attribute, options do |form, attr, value|
13
13
  @form = form
14
14
  @model = form.send(model_name)
15
15
  @klass = @model.class
@@ -1,3 +1,3 @@
1
1
  module Activeform
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -1,66 +1,106 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe ActiveForm do
4
- class Form
5
- include ActiveForm::Form
6
- properties :name, on: :user
7
- properties :title, on: :category
4
+ context 'backed by models' do
5
+ class Form
6
+ include ActiveForm::Form
7
+ properties :name, on: :user
8
+ properties :title, on: :category
8
9
 
9
- attr_accessor :user, :category
10
+ attr_accessor :user, :category
10
11
 
11
- self.main_model = :user
12
- end
13
-
14
- describe ".main_class" do
15
- it "reflect assoctions of the main model" do
16
- user = User.new
17
- category = Category.new
18
- user.categories = [category]
19
- expect(Form.reflect_on_association(:has_many)).to eq \
20
- User.reflect_on_association(:has_many)
12
+ self.main_model = :user
21
13
  end
22
14
 
23
- context "when a main class is specified" do
24
- it "take the specified class" do
25
- Form.main_class = Category
26
- expect(Form.main_class).to eq Category
15
+ describe ".main_class" do
16
+ it "reflect assoctions of the main model" do
17
+ user = User.new
18
+ category = Category.new
19
+ user.categories = [category]
20
+ expect(Form.reflect_on_association(:has_many)).to eq \
21
+ User.reflect_on_association(:has_many)
22
+ end
23
+
24
+ context "when a main class is specified" do
25
+ it "take the specified class" do
26
+ Form.main_class = Category
27
+ expect(Form.main_class).to eq Category
28
+ end
29
+ end
30
+
31
+ context "when there is only a main model specified" do
32
+ it "build the main class from the main model" do
33
+ Form.main_model = :category
34
+ expect(Form.main_class).to eq Category
35
+ end
27
36
  end
28
37
  end
29
38
 
30
- context "when there is only a main model specified" do
31
- it "build the main class from the main model" do
32
- Form.main_model = :category
33
- expect(Form.main_class).to eq Category
39
+ describe "#fill_attributes" do
40
+ it "assign variable to models" do
41
+ user = User.new
42
+ category = Category.new
43
+ form = Form.new(user: user, category: category)
44
+ form.fill_attributes(name: "Martin")
45
+ expect(user.name).to eq "Martin"
34
46
  end
35
47
  end
36
- end
37
48
 
38
- describe "#fill_attributes" do
39
- it "assign variable to models" do
40
- user = User.new
41
- category = Category.new
42
- form = Form.new(user: user, category: category)
43
- form.fill_attributes(name: "Martin")
44
- expect(user.name).to eq "Martin"
49
+ describe "#save" do
50
+ context "when the form is valid" do
51
+ context "when no block is given" do
52
+ it "save all models" do
53
+ user = User.new
54
+ category = Category.new
55
+ form = Form.new(user: user, category: category)
56
+ expect(user).to receive(:save)
57
+ expect(category).to receive(:save)
58
+ form.save
59
+ end
60
+
61
+ it "return true" do
62
+ form = Form.new(user: User.new, category: Category.new)
63
+ allow(form).to receive(:valid?).and_return(true)
64
+ expect(form.save).to eq true
65
+ end
66
+ end
67
+
68
+ context "when a block is given" do
69
+ it "use the block" do
70
+ user = User.new
71
+ form = Form.new(user: user, category: Category.new)
72
+ allow(form).to receive(:valid?).and_return(true)
73
+ expect(user).to receive(:process)
74
+ form.save { |f| f.user.process }
75
+ end
76
+ end
77
+ end
78
+
79
+ context "when the form is invalid" do
80
+ it "return false" do
81
+ form = Form.new(user: User.new, category: Category.new)
82
+ allow(form).to receive(:valid?).and_return(false)
83
+ expect(form.save).to eq false
84
+ end
85
+ end
45
86
  end
46
- end
47
87
 
48
- describe "#save" do
49
- context "when the form is valid" do
88
+ describe "#save!" do
50
89
  context "when no block is given" do
51
90
  it "save all models" do
52
91
  user = User.new
53
92
  category = Category.new
54
93
  form = Form.new(user: user, category: category)
55
- expect(user).to receive(:save)
56
- expect(category).to receive(:save)
57
- form.save
94
+ expect(user).to receive(:save!)
95
+ expect(category).to receive(:save!)
96
+ form.save!
58
97
  end
59
98
 
60
- it "return true" do
99
+ it "is surrounded by a transaction" do
100
+ expect(ActiveRecord::Base).to receive(:transaction).at_least(:once).
101
+ and_yield
61
102
  form = Form.new(user: User.new, category: Category.new)
62
- allow(form).to receive(:valid?).and_return(true)
63
- expect(form.save).to eq true
103
+ form.save!
64
104
  end
65
105
  end
66
106
 
@@ -68,57 +108,119 @@ describe ActiveForm do
68
108
  it "use the block" do
69
109
  user = User.new
70
110
  form = Form.new(user: user, category: Category.new)
71
- allow(form).to receive(:valid?).and_return(true)
72
111
  expect(user).to receive(:process)
73
- form.save { |f| f.user.process }
112
+ form.save! { |f| f.user.process }
74
113
  end
75
114
  end
76
115
  end
77
116
 
78
- context "when the form is invalid" do
79
- it "return false" do
80
- form = Form.new(user: User.new, category: Category.new)
81
- allow(form).to receive(:valid?).and_return(false)
82
- expect(form.save).to eq false
117
+ describe "#main_model" do
118
+ it "give the main model" do
119
+ Form.main_model = :category
120
+ category = Category.new
121
+ form = Form.new(user: User.new, category: category)
122
+ expect(form.main_model).to eq category
83
123
  end
84
124
  end
85
- end
86
125
 
87
- describe "#save!" do
88
- context "when no block is given" do
89
- it "save all models" do
90
- user = User.new
91
- category = Category.new
92
- form = Form.new(user: user, category: category)
93
- expect(user).to receive(:save!)
94
- expect(category).to receive(:save!)
126
+ describe "#persisted?" do
127
+ it "should be false when not saved" do
128
+ form = Form.new(user: User.new, category: Category.new)
129
+ expect(form.persisted?).to eq false
130
+ end
131
+
132
+ it "should be true when not saved" do
133
+ form = Form.new(user: User.new, category: Category.new)
95
134
  form.save!
135
+ expect(form.persisted?).to eq true
136
+ end
137
+ end
138
+
139
+ describe "#new_record?" do
140
+ it "should be true when not saved" do
141
+ form = Form.new(user: User.new, category: Category.new)
142
+ expect(form.new_record?).to eq true
96
143
  end
97
144
 
98
- it "is surrounded by a transaction" do
99
- expect(ActiveRecord::Base).to receive(:transaction).at_least(:once).
100
- and_yield
145
+ it "should be false when not saved" do
101
146
  form = Form.new(user: User.new, category: Category.new)
102
147
  form.save!
148
+ expect(form.new_record?).to eq false
103
149
  end
104
150
  end
105
151
 
106
- context "when a block is given" do
107
- it "use the block" do
108
- user = User.new
109
- form = Form.new(user: user, category: Category.new)
110
- expect(user).to receive(:process)
111
- form.save! { |f| f.user.process }
152
+ describe "class method #alias_method" do
153
+ class AliasForm
154
+ include ActiveForm::Form
155
+ properties :name, on: :user
156
+ alias_property :full_name, :name
157
+ self.main_model = :user
158
+ end
159
+
160
+ subject do
161
+ user = User.new(name: 'John')
162
+ AliasForm.new(user: user)
163
+ end
164
+
165
+ it "should allow alias name to be used for read operations" do
166
+ expect(subject.full_name).to eq 'John'
167
+ end
168
+
169
+ it "should allow alias name to be used for write operations" do
170
+ subject.full_name = 'Mike'
171
+ expect(subject.full_name).to eq 'Mike'
112
172
  end
113
173
  end
114
174
  end
115
175
 
116
- describe "#main_model" do
117
- it "give the main model" do
118
- Form.main_model = :category
119
- category = Category.new
120
- form = Form.new(user: User.new, category: category)
121
- expect(form.main_model).to eq category
176
+ context 'without any underlying models' do
177
+ class FormNoModels
178
+ include ActiveForm::Form
179
+ properties :name, :title
180
+ end
181
+
182
+ it 'it should allow initialization without any arg' do
183
+ form = FormNoModels.new
184
+ expect(form.name).to eq nil
185
+ expect(form.title).to eq nil
186
+ end
187
+
188
+ it 'it should args to be set on initialize' do
189
+ form = FormNoModels.new(name: 'John', title: 'CEO')
190
+ expect(form.name).to eq 'John'
191
+ expect(form.title).to eq 'CEO'
192
+ end
193
+
194
+ it 'should raise an exception on save' do
195
+ expect do
196
+ FormNoModels.new.save
197
+ end.to raise_exception(ActiveForm::CannotBePersisted)
198
+ end
199
+
200
+ it 'should raise an exception on save!' do
201
+ expect do
202
+ FormNoModels.new.save!
203
+ end.to raise_exception(ActiveForm::CannotBePersisted)
204
+ end
205
+
206
+ it 'should delegate class method #model_name' do
207
+ expect(FormNoModels.model_name.to_s).to eq 'FormNoModels'
208
+ end
209
+
210
+ it 'should delegate #to_key' do
211
+ expect(FormNoModels.new.to_key).to eq nil
212
+ end
213
+
214
+ it 'should delegate #to_param' do
215
+ expect(FormNoModels.new.to_param).to eq nil
216
+ end
217
+
218
+ it 'should delegate #id' do
219
+ expect(FormNoModels.new.id).to eq nil
220
+ end
221
+
222
+ it 'should always return false to #persisted?' do
223
+ expect(FormNoModels.new.persisted?).to be_false
122
224
  end
123
225
  end
124
226
  end
@@ -1,17 +1,17 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe ActiveForm::ValidateUniqueness do
4
- class Form
4
+ class ValidateUniquenessForm
5
5
  include ActiveForm::Form
6
6
  include ActiveForm::ValidateUniqueness
7
7
  properties :name, on: :user
8
- validates_uniqueness_of :name, :user
8
+ validates_uniqueness_of :name, :user, allow_nil: true
9
9
  end
10
10
 
11
11
  context "when there is no user" do
12
12
  it "is valid" do
13
13
  user = User.new
14
- form = Form.new(user: user)
14
+ form = ValidateUniquenessForm.new(user: user)
15
15
  expect(form).to be_valid
16
16
  end
17
17
  end
@@ -20,7 +20,7 @@ describe ActiveForm::ValidateUniqueness do
20
20
  context "when the user is saved" do
21
21
  it "is valid" do
22
22
  user = User.create(name: 'name')
23
- form = Form.new(user: user)
23
+ form = ValidateUniquenessForm.new(user: user)
24
24
  expect(form).to be_valid
25
25
  end
26
26
  end
@@ -29,7 +29,7 @@ describe ActiveForm::ValidateUniqueness do
29
29
  it "is not valid" do
30
30
  User.create(name: 'name')
31
31
  user = User.new(name: 'name')
32
- form = Form.new(user: user)
32
+ form = ValidateUniquenessForm.new(user: user)
33
33
  expect(form).to_not be_valid
34
34
  end
35
35
  end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'ActiveForm ActiveRecord validators' do
4
+ context 'backed by models' do
5
+ class ValidationForm
6
+ include ActiveForm::Form
7
+ properties :name, on: :user
8
+ validates_presence_of :name
9
+ end
10
+
11
+ context "when name is empty" do
12
+ it "is not valid" do
13
+ user = User.new
14
+ form = ValidationForm.new(user: user)
15
+ expect(form).to_not be_valid
16
+ end
17
+ end
18
+
19
+ context "when name is filled in" do
20
+ it "is valid" do
21
+ user = User.new
22
+ user.name = 'John'
23
+ form = ValidationForm.new(user: user)
24
+ expect(form).to be_valid
25
+ end
26
+ end
27
+ end
28
+
29
+ context 'without any underlying models' do
30
+ class ValidationFormNoModels
31
+ include ActiveForm::Form
32
+ properties :name
33
+ validates_presence_of :name
34
+ end
35
+
36
+ context "when name is empty" do
37
+ it "is not valid" do
38
+ form = ValidationFormNoModels.new
39
+ expect(form).to_not be_valid
40
+ end
41
+ end
42
+
43
+ context "when name is filled in" do
44
+ it "is valid" do
45
+ form = ValidationFormNoModels.new(name: 'John')
46
+ expect(form).to be_valid
47
+ end
48
+ end
49
+ end
50
+ end
@@ -4,9 +4,14 @@ require 'database_cleaner'
4
4
 
5
5
  ActiveRecord::Base.establish_connection(
6
6
  :adapter => "sqlite3",
7
- :database => "#{Dir.pwd}/database.sqlite3"
7
+ :database => ':memory:'
8
8
  )
9
9
 
10
+ ['CREATE TABLE categories(id INTEGER PRIMARY KEY, title, user_id)',
11
+ 'CREATE TABLE users(id INTEGER PRIMARY KEY, name)'].each do |sql|
12
+ ActiveRecord::Base.connection.execute sql
13
+ end
14
+
10
15
  class User < ActiveRecord::Base
11
16
  has_many :categories
12
17
  end
@@ -30,3 +35,6 @@ RSpec.configure do |config|
30
35
  end
31
36
  end
32
37
 
38
+ # hide deprecation warnings, see http://stackoverflow.com/questions/20361428/rails-i18n-validation-deprecation-warning
39
+ I18n.config.enforce_available_locales = true
40
+
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activeform-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Guirec Corbel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-23 00:00:00.000000000 Z
11
+ date: 2014-03-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: sqlite3
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +66,34 @@ dependencies:
52
66
  - - "~>"
53
67
  - !ruby/object:Gem::Version
54
68
  version: '2'
69
+ - !ruby/object:Gem::Dependency
70
+ name: activerecord
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3'
83
+ - !ruby/object:Gem::Dependency
84
+ name: database_cleaner
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.2'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.2'
55
97
  description: Enable to use the concept of form objects with ActiveModel
56
98
  email:
57
99
  - guirec.corbel@gmail.com
@@ -63,11 +105,13 @@ files:
63
105
  - Rakefile
64
106
  - lib/activeform-rails.rb
65
107
  - lib/activeform-rails/form.rb
108
+ - lib/activeform-rails/unpersistent_model.rb
66
109
  - lib/activeform-rails/validate_uniqueness.rb
67
110
  - lib/activeform-rails/version.rb
68
111
  - lib/tasks/activeform_tasks.rake
69
112
  - spec/activeform-rails/form_spec.rb
70
113
  - spec/activeform-rails/validate_uniqueness_spec.rb
114
+ - spec/activeform-rails/validation_spec.rb
71
115
  - spec/dummy/Gemfile
72
116
  - spec/dummy/Gemfile.lock
73
117
  - spec/dummy/README.rdoc
@@ -157,6 +201,7 @@ specification_version: 4
157
201
  summary: Form Objects for ActiveModel
158
202
  test_files:
159
203
  - spec/activeform-rails/validate_uniqueness_spec.rb
204
+ - spec/activeform-rails/validation_spec.rb
160
205
  - spec/activeform-rails/form_spec.rb
161
206
  - spec/spec_helper.rb
162
207
  - spec/dummy/config.ru