mini_form 0.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6d427b889425b8c2acd15827c88bc61430a70652
4
+ data.tar.gz: 582b6cf7164ab75b6f4df2f306eeb5580d9a0f3c
5
+ SHA512:
6
+ metadata.gz: 9e0f762fd07558b4c30386d9cd2a9a51b8855efb0279bb70b7f842d0e3748d7a413a0f449a31eb1d448e8b93c649930b3b90dbbb9ece8a4151ae013dd0f4d096
7
+ data.tar.gz: d23461cd996d47cbbdfe7efd5219aed986a72e83c5693e6d1e413927fa947786c200bd1e6bb1cd227573af8f4b1a8c9be7d89926111b4fc3bbd8fbd5efeec448
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --colour
2
+ --format=documentation
@@ -0,0 +1,24 @@
1
+ require: rubocop-rspec
2
+
3
+ AllCops:
4
+ RunRailsCops: true
5
+ Exclude:
6
+ - example/db/**/*
7
+ - example/config/**/*
8
+ - search_object.gemspec
9
+
10
+ # Disables "Line is too long"
11
+ LineLength:
12
+ Enabled: false
13
+
14
+ # Disables "Missing top-level class documentation comment"
15
+ Documentation:
16
+ Enabled: false
17
+
18
+ # Disables "Use each_with_object instead of inject"
19
+ Style/EachWithObject:
20
+ Enabled: false
21
+
22
+ # Disables "Prefer reduce over inject."
23
+ Style/CollectionMethods:
24
+ Enabled: false
@@ -0,0 +1,10 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0
4
+ - 2.1
5
+ - 2.2
6
+ script:
7
+ - bundle exec rubocop
8
+ - bundle exec rspec spec
9
+ notifications:
10
+ email: false
@@ -0,0 +1,5 @@
1
+ # Changelog
2
+
3
+ ## Version 0.1.0
4
+
5
+ * Initial release
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013-2015 Radoslav Stankov
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,261 @@
1
+ [![Gem Version](https://badge.fury.io/rb/mini_form.png)](http://badge.fury.io/rb/mini_form)
2
+ [![Code Climate](https://codeclimate.com/github/RStankov/MiniForm.png)](https://codeclimate.com/github/RStankov/MiniForm)
3
+ [![Build Status](https://secure.travis-ci.org/RStankov/MiniForm.png)](http://travis-ci.org/RStankov/MiniForm)
4
+ [![Code coverage](https://coveralls.io/repos/RStankov/MiniForm/badge.png?branch=master)](https://coveralls.io/r/RStankov/MiniForm)
5
+
6
+ # MiniForm
7
+
8
+ Helpers for dealing with form objects and nested forms.
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ ```ruby
15
+ gem 'mini_form'
16
+ ```
17
+
18
+ And then execute:
19
+
20
+ $ bundle
21
+
22
+ Or install it yourself as:
23
+
24
+ $ gem install mini_form
25
+
26
+ ## Usage
27
+
28
+ ```ruby
29
+ class ProductForm
30
+ include MiniForm::Model
31
+
32
+ attributes :id, :name, :price, :description
33
+
34
+ validates :name, :price, :description, presence: true
35
+
36
+ # called after successful validations in update
37
+ def perform
38
+ @id = ExternalService.create(attributes)
39
+ end
40
+ end
41
+ ```
42
+
43
+ ```ruby
44
+ class ProductsController < ApplicationController
45
+ def create
46
+ @product = ProductForm.new
47
+
48
+ if @product.update(product_params)
49
+ redirect_to product_path(product.id)
50
+ else
51
+ render :edit
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ def product_params
58
+ params.require(:product).permit(:name, :price, :description)
59
+ end
60
+ end
61
+ ```
62
+
63
+ ### Delegated attributes
64
+
65
+ Attributes can be delegated to a sub object.
66
+
67
+ ```ruby
68
+ class SignUpForm
69
+ include MiniForm::Model
70
+
71
+ attr_reader :account, :user
72
+
73
+ attributes :name, :email, delegate: :user
74
+ attributes :company_name, :plan, delegate: :account
75
+
76
+ validates :name, :email, :company_name, :plan, presence: true
77
+
78
+ def initialize
79
+ @account = Account.new
80
+ @user = User.new account: @account
81
+ end
82
+
83
+ def perform
84
+ user.save!
85
+ account.save!
86
+ end
87
+ end
88
+ ```
89
+
90
+ ```ruby
91
+ form = SignUpForm.new
92
+ form.name = 'name' # => form.user.name = 'name'
93
+ form.name # => form.user.name
94
+ form.plan = 'free' # => form.account.plan = 'free'
95
+ form.plan # => form.account.plan
96
+ ```
97
+
98
+ ### Nested validator
99
+
100
+ `mini_form/nested` validator runs validations on the given model and copies errors to the form object.
101
+
102
+ ```ruby
103
+ class SignUpForm
104
+ include MiniForm::Model
105
+
106
+ attr_reader :account, :user
107
+
108
+ attributes :name, :email, delegate: :user
109
+ attributes :company_name, :plan, delegate: :account
110
+
111
+ validates :account, :user, 'mini_form/nested' => true
112
+
113
+ def initialize
114
+ @account = Account.new
115
+ @user = User.new account: @account
116
+ end
117
+
118
+ def perform
119
+ account.save!
120
+ user.save!
121
+ end
122
+ end
123
+ ```
124
+
125
+ ### Nested models
126
+
127
+ Combines delegated attributes and nested validation into a single call.
128
+
129
+ ```ruby
130
+ class SignUpForm
131
+ include MiniForm::Model
132
+
133
+ modal :user, attributes: %i(name email)
134
+ model :account, attributes: %i(company_name plan)
135
+
136
+ def initialize
137
+ @account = Account.new
138
+ @user = User.new account: @account
139
+ end
140
+
141
+ def perform
142
+ account.save!
143
+ user.save!
144
+ end
145
+ end
146
+ ```
147
+
148
+ ### Auto saving nested models
149
+
150
+ In most of the time `perform` is just calling `save!`.
151
+
152
+ ```ruby
153
+ class SignUpForm
154
+ include MiniForm::Model
155
+
156
+ modal :user, attributes: %i(name email), save: true
157
+ model :account, attributes: %i(company_name plan), save: true
158
+
159
+ def initialize
160
+ @account = Account.new
161
+ @user = User.new account: @account
162
+ end
163
+ end
164
+ ```
165
+
166
+ ### Before/after callbacks
167
+
168
+ ```ruby
169
+ class SignUpForm
170
+ include MiniForm::Model
171
+
172
+ # ... code
173
+
174
+ before_update :run_before_update
175
+ after_update :run_after_update
176
+
177
+ private
178
+
179
+ def run_before_update
180
+ # ...
181
+ end
182
+
183
+ def run_after_update
184
+ # ...
185
+ end
186
+
187
+ # alternatively you can overwrite "before_update"
188
+ def before_update
189
+ end
190
+
191
+ # alternatively you can overwrite "after_update"
192
+ def after_update
193
+ end
194
+ end
195
+ ```
196
+
197
+ ### Methods
198
+
199
+ <table>
200
+ <tr>
201
+ <th>Method</th>
202
+ <th>Description</th>
203
+ </tr>
204
+ <tr>
205
+ <td>.model</td>
206
+ <td>Defines a sub object for the form</td>
207
+ </tr>
208
+ <tr>
209
+ <td>.attributes</td>
210
+ <td>Defines an attribute, it can delegate to sub object</td>
211
+ </tr>
212
+ <tr>
213
+ <td>#initialize</td>
214
+ <td>Meant to be overwritten. By defaults calls `attributes=`</td>
215
+ </tr>
216
+ <tr>
217
+ <td>#attributes=</td>
218
+ <td>Sets values of all attributes</td>
219
+ </tr>
220
+ <tr>
221
+ <td>#attributes</td>
222
+ <td>Returns all attributes of the form</td>
223
+ </tr>
224
+ <tr>
225
+ <td>#update</td>
226
+ <td>Sets attributes, calls validations, saves models and `perform`</td>
227
+ </tr>
228
+ <tr>
229
+ <td>#update!</td>
230
+ <td>Calls `update`. If validation fails, it raises an error</td>
231
+ </tr>
232
+ <tr>
233
+ <td>#perform</td>
234
+ <td>Meant to be overwritten. Doesn't do anything by default</td>
235
+ </tr>
236
+ <tr>
237
+ <td>#before_update</td>
238
+ <td>Meant to be overwritten.</td>
239
+ </tr>
240
+ <tr>
241
+ <td>#after_update</td>
242
+ <td>Meant to be overwritten.</td>
243
+ </tr>
244
+ <tr>
245
+ <td>#transaction</td>
246
+ <td>If ActiveRecord is available, wraps `perform` in transaction.</td>
247
+ </tr>
248
+ </table>
249
+
250
+ ## Contributing
251
+
252
+ 1. Fork it
253
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
254
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
255
+ 4. Push to the branch (`git push origin my-new-feature`)
256
+ 5. Run the tests (`rake`)
257
+ 6. Create new Pull Request
258
+
259
+ ## License
260
+
261
+ **[MIT License](https://github.com/RStankov/MiniForm/blob/master/LICENSE.txt)**
@@ -0,0 +1,8 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ require 'rubocop/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+ RuboCop::RakeTask.new(:rubocop)
7
+
8
+ task default: [:rubocop, :spec]
@@ -0,0 +1,7 @@
1
+ require 'mini_form/version'
2
+ require 'mini_form/model'
3
+ require 'mini_form/errors'
4
+ require 'mini_form/nested_validator'
5
+
6
+ module MiniForm
7
+ end
@@ -0,0 +1,4 @@
1
+ module MiniForm
2
+ class InvalidForm < StandardError
3
+ end
4
+ end
@@ -0,0 +1,120 @@
1
+ require 'active_support/all'
2
+ require 'active_model'
3
+
4
+ module MiniForm
5
+ module Model
6
+ def self.included(base)
7
+ base.class_eval do
8
+ include ActiveModel::Validations
9
+ include ActiveModel::Conversion
10
+
11
+ extend ActiveModel::Naming
12
+ extend ActiveModel::Callbacks
13
+
14
+ extend ClassMethods
15
+
16
+ define_model_callbacks :update
17
+
18
+ before_update :before_update
19
+ after_update :after_update
20
+ end
21
+ end
22
+
23
+ def initialize(attributes = {})
24
+ self.attributes = attributes
25
+ end
26
+
27
+ def persisted?
28
+ false
29
+ end
30
+
31
+ def attributes=(attributes)
32
+ attributes.slice(*self.class.attribute_names).each do |name, value|
33
+ public_send "#{name}=", value
34
+ end
35
+ end
36
+
37
+ def attributes
38
+ Hash[self.class.attribute_names.map { |name| [name, public_send(name)] }]
39
+ end
40
+
41
+ def update(attributes = {})
42
+ self.attributes = attributes unless attributes.empty?
43
+
44
+ return false unless valid?
45
+
46
+ run_callbacks :update do
47
+ transaction do
48
+ save_models
49
+ perform
50
+ end
51
+ end
52
+
53
+ true
54
+ end
55
+
56
+ def update!(attributes = {})
57
+ fail InvalidForm unless update attributes
58
+ self
59
+ end
60
+
61
+ private
62
+
63
+ def transaction(&block)
64
+ if defined? ActiveRecord
65
+ ActiveRecord::Base.transaction(&block)
66
+ else
67
+ yield
68
+ end
69
+ end
70
+
71
+ # :api: private
72
+ def save_models
73
+ self.class.models_to_save.each { |model_name| public_send(model_name).save! }
74
+ end
75
+
76
+ def perform
77
+ # noop
78
+ end
79
+
80
+ def before_update
81
+ # noop
82
+ end
83
+
84
+ def after_update
85
+ # noop
86
+ end
87
+
88
+ module ClassMethods
89
+ # :api: private
90
+ def attribute_names
91
+ @attribute_names ||= []
92
+ end
93
+
94
+ # :api: private
95
+ def models_to_save
96
+ @models_to_save ||= []
97
+ end
98
+
99
+ def attributes(*attributes, delegate: nil, prefix: nil, allow_nil: nil)
100
+ attribute_names.push(*attributes)
101
+
102
+ if delegate.nil?
103
+ attr_accessor(*attributes)
104
+ else
105
+ self.delegate(*attributes, to: delegate, prefix: prefix, allow_nil: allow_nil)
106
+ self.delegate(*attributes.map { |attr| "#{attr}=" }, to: delegate, prefix: prefix, allow_nil: allow_nil)
107
+ end
108
+ end
109
+
110
+ def model(name, attributes: [], prefix: nil, allow_nil: nil, save: false)
111
+ attributes(name)
112
+ attributes(*attributes, delegate: name, prefix: prefix, allow_nil: allow_nil) unless attributes.empty?
113
+
114
+ validates name, 'mini_form/nested' => true
115
+
116
+ models_to_save << name if save
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,13 @@
1
+ require 'active_model'
2
+
3
+ module MiniForm
4
+ class NestedValidator < ActiveModel::EachValidator
5
+ def validate_each(record, _, relation)
6
+ return if relation.valid?
7
+
8
+ relation.errors.each do |name, value|
9
+ record.errors.add name, value
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,3 @@
1
+ module MiniForm
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'mini_form/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'mini_form'
8
+ spec.version = MiniForm::VERSION
9
+ spec.authors = ['Radoslav Stankov']
10
+ spec.email = ['rstankov@gmail.com']
11
+ spec.description = 'Sugar around ActiveModel::Model'
12
+ spec.summary = 'Easy to use form objects in Rails projects'
13
+ spec.homepage = 'https://github.com/RStankov/MiniForm'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
17
+ spec.executables = spec.files.grep(/^bin\//) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(/^(spec)\//)
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_dependency 'activemodel', '~> 4.0'
22
+
23
+ spec.add_development_dependency 'bundler', '~> 1.3'
24
+ spec.add_development_dependency 'rake'
25
+ spec.add_development_dependency 'rspec', '~> 2.14'
26
+ spec.add_development_dependency 'rspec-mocks', '>= 2.12.3'
27
+ spec.add_development_dependency 'coveralls'
28
+ spec.add_development_dependency 'rubocop'
29
+ spec.add_development_dependency 'rubocop-rspec'
30
+ end
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ module MiniForm
4
+ describe NestedValidator do
5
+ class User
6
+ include ActiveModel::Model
7
+
8
+ attr_accessor :name
9
+
10
+ validates :name, presence: true
11
+ end
12
+
13
+ class Record
14
+ include ActiveModel::Validations
15
+
16
+ attr_accessor :user
17
+
18
+ def initialize(user)
19
+ @user = user
20
+ end
21
+ end
22
+
23
+ let(:validator) { NestedValidator.new(attributes: [:user]) }
24
+ let(:user) { User.new }
25
+ let(:record) { Record.new(user) }
26
+
27
+ it 'copies errors from submodel to model' do
28
+ validator.validate(record)
29
+
30
+ expect(record.errors[:name]).not_to be_blank
31
+ end
32
+
33
+ it 'does not copy errors when there are not any' do
34
+ user.name = 'valid name'
35
+
36
+ validator.validate(record)
37
+
38
+ expect(record.errors[:name]).to be_blank
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,238 @@
1
+ require 'spec_helper'
2
+
3
+ module MiniForm
4
+ describe Model do
5
+ let(:user) { User.new name: 'Name' }
6
+
7
+ class User
8
+ include ActiveModel::Model
9
+
10
+ attr_accessor :name
11
+
12
+ validates :name, presence: true
13
+ end
14
+
15
+ Example = Class.new do
16
+ include Model
17
+ attributes :name, :price
18
+ end
19
+
20
+ ExampleWithDelegate = Class.new do
21
+ include Model
22
+
23
+ attr_reader :user
24
+
25
+ attributes :name, delegate: :user
26
+
27
+ def initialize(user)
28
+ @user = user
29
+ end
30
+ end
31
+
32
+ ExampleWithModel = Class.new do
33
+ include Model
34
+
35
+ model :user, attributes: %i(name)
36
+ end
37
+
38
+ describe 'acts as ActiveModel' do
39
+ include ActiveModel::Lint::Tests
40
+
41
+ before do
42
+ @model = Example.new
43
+ end
44
+
45
+ def assert(condition, message = nil)
46
+ expect(condition).to be_truthy, message
47
+ end
48
+
49
+ def assert_kind_of(expected_kind, object, message = nil)
50
+ expect(object).to be_kind_of(expected_kind), message
51
+ end
52
+
53
+ def assert_equal(expected_value, value, message = nil)
54
+ expect(value).to eq(expected_value), message
55
+ end
56
+
57
+ ActiveModel::Lint::Tests.public_instance_methods.map(&:to_s).grep(/^test/).each do |method|
58
+ example(method.gsub('_', ' ')) { send method }
59
+ end
60
+ end
61
+
62
+ describe '.attributes' do
63
+ it 'generates getters' do
64
+ object = Example.new name: 'value'
65
+ expect(object.name).to eq 'value'
66
+ end
67
+
68
+ it 'generates setters' do
69
+ object = Example.new
70
+ object.name = 'value'
71
+
72
+ expect(object.name).to eq 'value'
73
+ end
74
+
75
+ it 'can delegate getter' do
76
+ object = ExampleWithDelegate.new user
77
+ expect(object.name).to eq user.name
78
+ end
79
+
80
+ it 'can delegate setter' do
81
+ object = ExampleWithDelegate.new user
82
+
83
+ object.name = 'New Name'
84
+
85
+ expect(object.name).to eq 'New Name'
86
+ expect(user.name).to eq 'New Name'
87
+ end
88
+ end
89
+
90
+ describe '.model' do
91
+ it 'generates model accessors' do
92
+ object = ExampleWithModel.new user: user
93
+ expect(object.user).to eq user
94
+ end
95
+
96
+ it 'can delegate model attributes' do
97
+ object = ExampleWithModel.new user: user
98
+ expect(object.name).to eq user.name
99
+ end
100
+
101
+ it 'performs nested validation for model' do
102
+ user = User.new
103
+ object = ExampleWithModel.new user: user
104
+
105
+ expect(object).not_to be_valid
106
+ expect(object.errors[:name]).to be_present
107
+ end
108
+ end
109
+
110
+ describe '.attributes_names' do
111
+ it 'returns attribute names' do
112
+ expect(Example.attribute_names).to eq %i(name price)
113
+ end
114
+ end
115
+
116
+ describe '#initialize' do
117
+ it 'can be called with no arguments' do
118
+ expect { Example.new }.not_to raise_error
119
+ end
120
+
121
+ it 'assign the passed attributes' do
122
+ object = Example.new price: '$5'
123
+
124
+ expect(object.price).to eq '$5'
125
+ end
126
+
127
+ it 'ignores invalid attributes' do
128
+ expect { Example.new invalid: 'attribute' }.not_to raise_error
129
+ end
130
+
131
+ it 'handles HashWithIndifferentAccess hashes' do
132
+ hash = ActiveSupport::HashWithIndifferentAccess.new 'price' => '$5'
133
+ object = Example.new hash
134
+
135
+ expect(object.price).to eq '$5'
136
+ end
137
+ end
138
+
139
+ describe '#attributes' do
140
+ it 'returns attributes' do
141
+ object = Example.new name: 'iPhone', price: '$5'
142
+ expect(object.attributes).to eq name: 'iPhone', price: '$5'
143
+ end
144
+ end
145
+
146
+ describe '#update' do
147
+ ExampleForUpdate = Class.new do
148
+ include Model
149
+
150
+ attributes :name
151
+
152
+ validates :name, presence: true
153
+ end
154
+
155
+ ExampleForSave = Class.new do
156
+ include Model
157
+
158
+ model :user, attributes: %i(name), save: true
159
+ end
160
+
161
+ it 'updates attributes' do
162
+ object = ExampleForUpdate.new name: 'value'
163
+
164
+ expect { object.update(name: 'new value') }.to change { object.name }.to 'new value'
165
+ end
166
+
167
+ it 'returns true when validations pass' do
168
+ object = ExampleForUpdate.new name: 'value'
169
+
170
+ expect(object.update).to eq true
171
+ end
172
+
173
+ it 'calls "perfom" method when validation pass' do
174
+ object = ExampleForUpdate.new name: 'value'
175
+
176
+ expect(object).to receive(:perform)
177
+
178
+ object.update
179
+ end
180
+
181
+ it 'calls "save" for the model' do
182
+ object = ExampleForSave.new user: user
183
+
184
+ allow(user).to receive(:save!)
185
+
186
+ object.update
187
+
188
+ expect(user).to have_received(:save!)
189
+ end
190
+
191
+ it 'supports update callbacks' do
192
+ object = ExampleForUpdate.new name: 'value'
193
+
194
+ expect(object).to receive(:before_update)
195
+ expect(object).to receive(:after_update)
196
+
197
+ object.update
198
+ end
199
+
200
+ it 'returns false when validations fail' do
201
+ object = ExampleForUpdate.new name: nil
202
+
203
+ expect(object.update).to eq false
204
+ end
205
+
206
+ it 'does not call "perfom" method when validation fail' do
207
+ object = ExampleForUpdate.new name: nil
208
+
209
+ expect(object).not_to receive(:perform)
210
+
211
+ object.update
212
+ end
213
+ end
214
+
215
+ describe '#update!' do
216
+ it 'returns self' do
217
+ object = Example.new
218
+ expect(object.update!).to eq object
219
+ end
220
+
221
+ it 'calls update with given arguments' do
222
+ object = Example.new
223
+
224
+ expect(object).to receive(:update).with(:attributes).and_return true
225
+
226
+ object.update! :attributes
227
+ end
228
+
229
+ it 'raises error when update fails' do
230
+ object = Example.new
231
+
232
+ allow(object).to receive(:update).and_return false
233
+
234
+ expect { object.update! }.to raise_error InvalidForm
235
+ end
236
+ end
237
+ end
238
+ end
@@ -0,0 +1,12 @@
1
+ require 'bundler/setup'
2
+
3
+ if ENV['TRAVIS']
4
+ require 'coveralls'
5
+ Coveralls.wear!
6
+ end
7
+
8
+ require 'mini_form'
9
+
10
+ RSpec.configure do |config|
11
+ config.expect_with(:rspec) { |c| c.syntax = :expect }
12
+ end
metadata ADDED
@@ -0,0 +1,177 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mini_form
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Radoslav Stankov
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-03-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activemodel
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '4.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.14'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2.14'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec-mocks
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: 2.12.3
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 2.12.3
83
+ - !ruby/object:Gem::Dependency
84
+ name: coveralls
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop-rspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description: Sugar around ActiveModel::Model
126
+ email:
127
+ - rstankov@gmail.com
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - ".gitignore"
133
+ - ".rspec"
134
+ - ".rubocop.yml"
135
+ - ".travis.yml"
136
+ - CHANGELOG.md
137
+ - Gemfile
138
+ - LICENSE.txt
139
+ - README.md
140
+ - Rakefile
141
+ - lib/mini_form.rb
142
+ - lib/mini_form/errors.rb
143
+ - lib/mini_form/model.rb
144
+ - lib/mini_form/nested_validator.rb
145
+ - lib/mini_form/version.rb
146
+ - mini_form.gemspec
147
+ - spec/mini_form/nested_validator_spec.rb
148
+ - spec/mini_form_spec.rb
149
+ - spec/spec_helper.rb
150
+ homepage: https://github.com/RStankov/MiniForm
151
+ licenses:
152
+ - MIT
153
+ metadata: {}
154
+ post_install_message:
155
+ rdoc_options: []
156
+ require_paths:
157
+ - lib
158
+ required_ruby_version: !ruby/object:Gem::Requirement
159
+ requirements:
160
+ - - ">="
161
+ - !ruby/object:Gem::Version
162
+ version: '0'
163
+ required_rubygems_version: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - ">="
166
+ - !ruby/object:Gem::Version
167
+ version: '0'
168
+ requirements: []
169
+ rubyforge_project:
170
+ rubygems_version: 2.4.5
171
+ signing_key:
172
+ specification_version: 4
173
+ summary: Easy to use form objects in Rails projects
174
+ test_files:
175
+ - spec/mini_form/nested_validator_spec.rb
176
+ - spec/mini_form_spec.rb
177
+ - spec/spec_helper.rb