tradesman 0.3.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: db5c2d7076e95ba6d615b720841bd7060498fd41
4
- data.tar.gz: 8e3c89647d347d22d91f8b6674b97365ce0615b9
3
+ metadata.gz: 88a8291acc6f38c6d19ff311c2c2ab950c755288
4
+ data.tar.gz: dca95fa986b0e498bec27f5205fbec416d547c78
5
5
  SHA512:
6
- metadata.gz: 7fda495879e02cc5199b8327879fae9fa7acbacd1aa2f6e3b94a8391482d3fb82b2a3a1e130006e3df9fcf0ddeeefdb423ad4f1b2e7b597d7c7fefeb473e3d9b
7
- data.tar.gz: d6868892dc9f4441426dbe234e3bafe40c38f83788e592b34e5a7caba9410071f280156e7466babd790c8989fcd3cd6ae86dae11d19d467c988d8d92f676a8aa
6
+ metadata.gz: e403a3da8460e086194e472c92d2827e2e132da3f2150dc26b7a7d248b476f851289f70e6fc95959efd7ee90646981eaaf29bd12a78c94c111fe918893b8563d
7
+ data.tar.gz: c601b711e3e59ae362c9fed58870c1b5e3f92e488963d49a9a956c27c0156e9869ce7520bdfc50e55d46643f4cd9ca67006efb26253523e3972fa2f4b178ba4e
data/README.md CHANGED
@@ -1,19 +1,28 @@
1
1
  # Tradesman
2
2
 
3
- Encapsulate common application behaviour with dynamically generated classes.
4
-
5
- Tradesman dynamically generates classes with human-readble names that handle the pass, fail, and invalid results of common create, update, and delete actions.
3
+ Tradesman lets you invoke human-readble classes that handle the pass, fail, and invalid cases of common create, update, and delete actions without having to write the code!
6
4
 
7
5
  ## Usage
8
6
 
9
7
  ```ruby
10
- # Simple - Returns an Outcome
11
- outcome = Tradesman::CreateUser.run(user_params)
8
+ # Simple - Returns a successful Outcome
9
+ outcome = Tradesman::CreateUser.go(user_params)
12
10
  outcome.success? #=> true
11
+ outcome.failure? #=> false
13
12
  outcome.result #=> User Entity
14
13
 
14
+ # With invalid parameters - returns an invalid Outcome
15
+ outcome = Tradesman::CreateUser.go(invalid_user_params)
16
+ outcome.success? #=> false
17
+ outcome.failure? #=> true
18
+ outcome.result #=> Error Class
19
+ outcome.type #=> :validation
20
+
21
+ # With invalid parameters - fail loudly!
22
+ outcome = Tradesman::CreateUser.go!(invalid_user_params) #=> raises Tradesman::Invalid or Tradesman::Failure
23
+
15
24
  # Passing a block - Well-suited for Controllers
16
- Tradesman::UpdateUser.run({ id: params[:id] }.merge(user_update_params)) do
25
+ Tradesman::UpdateUser.go(params[:id], user_update_params) do
17
26
  success do |result|
18
27
  render(text: 'true', status: 200)
19
28
  end
@@ -22,18 +31,70 @@ Tradesman::UpdateUser.run({ id: params[:id] }.merge(user_update_params)) do
22
31
  render(text: 'false', status: 404)
23
32
  end
24
33
 
25
- failure do |result|
34
+ failure do |error|
26
35
  render(text: 'false', status: 400)
27
36
  end
28
37
  end
29
38
 
30
- # Can also Delete
31
- Tradesman::DeleteUser.run(id: params[:id])
39
+ # Delete
40
+ Tradesman::DeleteUser.go(params[:id])
41
+
42
+ # Create as a child of an existing record
43
+ Tradesman::CreateUserForEmployer.go(employer, user_params)
44
+
45
+ # Create multiple records
46
+ Tradesman::CreateUser.go([user_params, user_params, user_params])
47
+
48
+ # Create multiple for a single parent
49
+ Tradesman::CreateUserForEmployer.go(employer, [user_params, user_params, user_params])
50
+
51
+ # Update multiple records with 1 set of parameters
52
+ Tradesman::UpdateUser.go([user1, user2, user3], update_params)
32
53
 
33
- # Or Create as a child of an existing record
34
- Tradesman::CreateUserForEmployer.run({ parent_id: employer_id }.merge(user_params))
54
+ # Update n records with n sets of parameters
55
+ # Whenever you pass an id, you can either pass the id itself,
56
+ # or an object that response to :id
57
+ update_params = {
58
+ user1.id => user1_params,
59
+ user2.id => user2_params,
60
+ user3.id => user3_params
61
+ }
62
+ Tradesman::UpdateUser.go(update_params.keys, update_params.values)
63
+
64
+
65
+ # Delete multiple records
66
+ Tradesman::DeleteUser.go([id1, id2, id3])
35
67
  ```
36
68
 
69
+ ## Parsing Rules
70
+
71
+ Classes have the following structure:
72
+
73
+ `Method` + `Record`
74
+
75
+ ```ruby
76
+ # Examples:
77
+ CreateUser
78
+ UpdateEmployer
79
+ DeleteBlogPost
80
+ ```
81
+
82
+ Where **Method** is one of `Create`, `Update`, or `Delete`, and **Record** is your model classname, CamelCased.
83
+ Note that model namespaces are ignored.
84
+
85
+ The only exception is when you create a record for a parent. These classes have the following structure:
86
+
87
+ `Method` + `Record` + `'For'` + `ParentRecord`
88
+
89
+ ```ruby
90
+ # Examples
91
+ CreateUserForEmployer
92
+ CreateInvoiceForCustomer
93
+ ```
94
+
95
+ Where 'For' is a string literal and **ParentRecord** is the parent model classname, CamelCased.
96
+
97
+
37
98
  ## Why is this necessary?
38
99
 
39
100
  At Onfido, we observed that many Create, Update and Delete actions we programmed were are simple and repeated (albeit with different records and parameter lists) in several locations. They can generally be broken in to the following steps:
@@ -51,7 +112,7 @@ def update
51
112
  return render(text: 'false', status: 404) unless @user
52
113
 
53
114
  @user.assign_attributes(user_params)
54
- return render(text: 'false', status: 400) unless @user.save
115
+ return render(text: 'false', status: 422) unless @user.save
55
116
 
56
117
  render 'user'
57
118
  end
@@ -68,14 +129,14 @@ Tradesman is designed to handle the above and a few other common use-cases to re
68
129
 
69
130
  Tradesman version of the above:
70
131
  ```ruby
71
- Tradesman::UpdateUser.run(user_params) do
132
+ Tradesman::UpdateUser.go(user_id, user_params) do
72
133
  success do |result|
73
134
  @user = result
74
135
  render 'user'
75
136
  end
76
137
 
77
138
  invalid do |error|
78
- render(text: 'false', status: 404)
139
+ render(text: error.message, status: 422)
79
140
  end
80
141
 
81
142
  failure { |result| render(text: 'false', status: 400) } # If you prefer one-liners
@@ -84,7 +145,7 @@ end
84
145
  private
85
146
 
86
147
  def user_params
87
- params.permit(:id, :first_name, :last_name)
148
+ params.permit(:first_name, :last_name, :email)
88
149
  end
89
150
  ```
90
151
 
@@ -94,8 +155,8 @@ The Tradesman version says exactly what it does, is cruft free, and is much quic
94
155
 
95
156
  **Define your adapter**
96
157
 
97
- _config/initializers/tradesman.rb_
98
158
  ```ruby
159
+ # config/initializers/tradesman.rb
99
160
  Tradesman.configure { |config| config.adapter = :active_record }
100
161
  ```
101
162
 
@@ -120,8 +181,8 @@ end
120
181
 
121
182
  In order to help Tradesman lazy load these models, you need to enable development mode and configure any namespaces:
122
183
 
123
- _config/initializers/tradesman.rb_
124
184
  ```ruby
185
+ # config/initializers/tradesman.rb
125
186
  Tradesman.configure do |config|
126
187
  config.adapter = :active_record
127
188
  config.development_mode = Rails.env.development?
@@ -11,6 +11,10 @@ module Tradesman
11
11
  template_class(class_args)
12
12
  end
13
13
 
14
+ def template_class(class_args)
15
+ raise Tradesman::MethodNotImplemented.new('You must implement template_class in a child class')
16
+ end
17
+
14
18
  private
15
19
 
16
20
  def class_args
@@ -5,11 +5,22 @@ module Tradesman
5
5
 
6
6
  def template_class(args)
7
7
  Class.new(::Tradesman::Template) do
8
+ include ::Tradesman::NewRecordsMultipleExecute
8
9
  @store = Tradesman.adapter.context_for_entity(args[:subject])
9
10
 
11
+ class << self
12
+ def go(params, *context, &block)
13
+ run_and_convert_exceptions { run(params, *context, &block) }
14
+ end
15
+
16
+ def go!(params, *context)
17
+ run_and_convert_exceptions { run!(params, *context) }
18
+ end
19
+ end
20
+
10
21
  private
11
22
 
12
- def execute(params)
23
+ def execute_single(params)
13
24
  self.class.adapter.create!(params)
14
25
  end
15
26
  end
@@ -5,6 +5,7 @@ module Tradesman
5
5
 
6
6
  def template_class(args)
7
7
  Class.new(::Tradesman::Template) do
8
+ include ::Tradesman::ExistingRecordsMultipleExecute
8
9
  @store = Tradesman.adapter.context_for_entity(args[:subject])
9
10
  @parent_store = Tradesman.adapter.context_for_entity(args[:parent])
10
11
  @parent_key = args[:parent]
@@ -19,14 +20,26 @@ module Tradesman
19
20
 
20
21
  private
21
22
 
22
- def execute(params)
23
- parent = self.class.parent_adapter.get!(params[:parent_id])
24
- self.class.adapter.create!(params.except(:parent_id).merge(relation_id => parent.id))
23
+ def execute_single(params)
24
+ parent = self.class.parent_adapter.get!(params[:id])
25
+ self.class.adapter.create!(params.except(:id).merge(relation_id => parent.id))
25
26
  end
26
27
 
27
28
  def relation_id
28
29
  "#{self.class.parent_key}_id"
29
30
  end
31
+
32
+ def execute_multiple(params_hash)
33
+ params = params_hash[:params] || params_hash.except(:id)
34
+
35
+ params.map do |params|
36
+ begin
37
+ execute_single({ id: params_hash[:id] }.merge(params))
38
+ rescue *self.class.expected_errors_map.keys => e
39
+ Horza::Entities::Single.new(id: params[:id], valid: false, message: e.message)
40
+ end
41
+ end
42
+ end
30
43
  end
31
44
  end
32
45
  end
@@ -5,11 +5,22 @@ module Tradesman
5
5
 
6
6
  def template_class(args)
7
7
  Class.new(::Tradesman::Template) do
8
+ include ::Tradesman::ExistingRecordsMultipleExecute
8
9
  @store = Tradesman.adapter.context_for_entity(args[:subject])
9
10
 
11
+ class << self
12
+ def go(obj, *context, &block)
13
+ run_and_convert_exceptions { run(tzu_params(obj, {}), *context, &block) }
14
+ end
15
+
16
+ def go!(obj, *context)
17
+ run_and_convert_exceptions { run!(tzu_params(obj, {}), *context) }
18
+ end
19
+ end
20
+
10
21
  private
11
22
 
12
- def execute(params)
23
+ def execute_single(params)
13
24
  self.class.adapter.delete!(params[:id])
14
25
  end
15
26
  end
@@ -5,11 +5,12 @@ module Tradesman
5
5
 
6
6
  def template_class(args)
7
7
  Class.new(::Tradesman::Template) do
8
+ include ::Tradesman::ExistingRecordsMultipleExecute
8
9
  @store = Tradesman.adapter.context_for_entity(args[:subject])
9
10
 
10
11
  private
11
12
 
12
- def execute(params)
13
+ def execute_single(params)
13
14
  self.class.adapter.update!(params[:id], params.except(:id))
14
15
  end
15
16
  end
@@ -0,0 +1,37 @@
1
+ module Tradesman
2
+ module ClassMethods
3
+ attr_reader :store
4
+
5
+ def adapter
6
+ Tradesman.adapter.new(store)
7
+ end
8
+
9
+ def go(obj, params, *context, &block)
10
+ run_and_convert_exceptions { run(tzu_params(obj, params), *context, &block) }
11
+ end
12
+
13
+ def go!(obj, params, *context)
14
+ run_and_convert_exceptions { run!(tzu_params(obj, params), *context) }
15
+ end
16
+
17
+ def tzu_params(obj, params)
18
+ { id: prepare_ids(obj) }.merge(prepare_params(params))
19
+ end
20
+
21
+ def prepare_ids(obj)
22
+ return id_from_obj(obj) unless obj.is_a? Array
23
+ obj.map { |object| id_from_obj(object) }
24
+ end
25
+
26
+ def id_from_obj(obj)
27
+ return obj.id if obj.respond_to? :id
28
+ raise Tradesman::InvalidId.new('ID must be an integer') unless obj.is_a? Integer
29
+ obj
30
+ end
31
+
32
+ def prepare_params(params)
33
+ return params unless params.is_a? Array
34
+ { params: params }
35
+ end
36
+ end
37
+ end
@@ -14,7 +14,7 @@ module Tradesman
14
14
  end
15
15
 
16
16
  def adapter
17
- raise ::Tradesman::Errors::Base.new('Adapter has not been configured') unless configuration.adapter
17
+ raise ::Tradesman::Base.new('Adapter has not been configured') unless configuration.adapter
18
18
  @adapter ||= configuration.adapter
19
19
  end
20
20
  end
@@ -32,7 +32,7 @@ module Tradesman
32
32
  end
33
33
 
34
34
  def namespaces=(namespaces)
35
- fail Tradesman::Errors::Base.new 'namespaces must be an array' unless namespaces.is_a? Array
35
+ fail Tradesman::Base.new 'namespaces must be an array' unless namespaces.is_a? Array
36
36
  Horza.configure { |config| config.namespaces = namespaces }
37
37
  @namespaces = namespaces
38
38
  end
@@ -0,0 +1,32 @@
1
+ module Tradesman
2
+ module ErrorHandling
3
+ def run_and_convert_exceptions(&block)
4
+ block.call
5
+ rescue *expected_errors_map.keys => e
6
+ raise tradesman_error_from_gem_error(e.class)
7
+ end
8
+
9
+ def tradesman_error_from_gem_error(gem_error)
10
+ expected_errors_map[gem_error]
11
+ end
12
+
13
+ def expected_errors_map
14
+ expected_tzu_errors_map.merge(expected_horza_errors_map)
15
+ end
16
+
17
+ def expected_tzu_errors_map
18
+ {
19
+ Tzu::Invalid => Tradesman::Invalid,
20
+ Tzu::Failure => Tradesman::Failure,
21
+ }
22
+ end
23
+
24
+ def expected_horza_errors_map
25
+ {
26
+ Horza::Errors::RecordNotFound => Tradesman::RecordNotFound,
27
+ Horza::Errors::RecordInvalid => Tradesman::RecordInvalid,
28
+ Horza::Errors::UnknownAttributeError => Tradesman::UnknownAttributeError
29
+ }
30
+ end
31
+ end
32
+ end
@@ -1,12 +1,25 @@
1
1
  module Tradesman
2
- module Errors
3
- class Base < StandardError
4
- end
2
+ class Base < StandardError
3
+ end
4
+
5
+ class MethodNotImplemented < StandardError
6
+ end
7
+
8
+ class InvalidId < StandardError
9
+ end
10
+
11
+ class Invalid < StandardError
12
+ end
13
+
14
+ class Failure < StandardError
15
+ end
5
16
 
6
- class MethodNotImplemented < StandardError
7
- end
17
+ class RecordNotFound < StandardError
18
+ end
19
+
20
+ class RecordInvalid < StandardError
21
+ end
8
22
 
9
- class RecordNotFound < StandardError
10
- end
23
+ class UnknownAttributeError < StandardError
11
24
  end
12
25
  end
@@ -0,0 +1,26 @@
1
+ module Tradesman
2
+ module ExistingRecordsMultipleExecute
3
+ private
4
+
5
+ def execute_multiple(params_hash)
6
+ params = params_hash[:params] || params_hash.except(:id)
7
+
8
+ params_hash[:id].to_enum.with_index.map do |id, index|
9
+ begin
10
+ execute_single(single_params(id, params, index))
11
+ rescue *self.class.expected_errors_map.keys => e
12
+ Horza::Entities::Single.new(id: id, valid: false, message: e.message)
13
+ end
14
+ end
15
+ end
16
+
17
+ def single_params(id, params, index)
18
+ { id: id }.merge(params_at_index(params, index))
19
+ end
20
+
21
+ def params_at_index(params, index)
22
+ return params unless params.is_a? Array
23
+ params[index]
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,15 @@
1
+ module Tradesman
2
+ module NewRecordsMultipleExecute
3
+ private
4
+
5
+ def execute_multiple(params_array)
6
+ params_array.map do |params|
7
+ begin
8
+ execute_single(params)
9
+ rescue *self.class.expected_errors_map.keys => e
10
+ Horza::Entities::Single.new(id: nil, valid: false, message: e.message)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -2,25 +2,24 @@ module Tradesman
2
2
  class Template
3
3
  include ::Tzu
4
4
  include ::Tzu::Validation
5
-
6
- class << self
7
- attr_reader :store
8
-
9
- def adapter
10
- Tradesman.adapter.new(store)
11
- end
12
- end
5
+ extend ::Tradesman::ClassMethods
6
+ extend ::Tradesman::ErrorHandling
13
7
 
14
8
  def call(params)
15
- execute(params)
16
- rescue Horza::Errors::RecordInvalid, Horza::Errors::RecordNotFound => e
9
+ return execute_single(params) unless (params.is_a?(Array) || params[:id].is_a?(Array) || params[:params].is_a?(Array))
10
+ execute_multiple(params)
11
+ rescue *self.class.expected_horza_errors_map.keys => e
17
12
  invalid! e
18
13
  end
19
14
 
20
15
  private
21
16
 
22
- def execute(params)
23
- raise Tradesman::Errors::MethodNotImplemented.new
17
+ def execute_single(params)
18
+ raise Tradesman::MethodNotImplemented.new('You must implement execute_single in a child class')
19
+ end
20
+
21
+ def execute_multiple(params_hash)
22
+ raise Tradesman::MethodNotImplemented.new('You must implement execute_multiple in a child class')
24
23
  end
25
24
  end
26
25
  end
data/lib/tradesman.rb CHANGED
@@ -1,44 +1,30 @@
1
1
  require 'horza'
2
2
  require 'tzu'
3
+ require 'tradesman/mixins/existing_records_multiple_execute'
4
+ require 'tradesman/mixins/new_records_multiple_execute'
3
5
  require 'tradesman/builders'
4
6
  require 'tradesman/builders/base'
5
7
  require 'tradesman/builders/create'
6
8
  require 'tradesman/builders/create_for_parent'
7
9
  require 'tradesman/builders/delete'
8
10
  require 'tradesman/builders/update'
11
+ require 'tradesman/class_methods'
9
12
  require 'tradesman/configuration'
10
13
  require 'tradesman/errors'
14
+ require 'tradesman/error_handling'
11
15
  require 'tradesman/parser'
12
- require 'tradesman/run_methods'
13
16
  require 'tradesman/template'
14
17
 
15
18
  module Tradesman
16
- extend Tradesman::Configuration
19
+ extend Configuration
17
20
 
18
21
  class << self
19
22
  attr_writer :configuration
20
23
 
21
- def included(base)
22
- base.class_eval do
23
- extend ::Tradesman::RunMethods
24
- end
25
- end
26
-
27
24
  def const_missing(class_name)
28
25
  parser = ::Tradesman::Parser.new(class_name)
29
26
  return super(class_name) unless parser.match?
30
27
  Builders.generate_class(parser)
31
28
  end
32
29
  end
33
-
34
- def run
35
- run!
36
- rescue ::Tradesman::Errors::Base
37
- end
38
-
39
- def run!
40
- call
41
- rescue *Tradesman.adapter.expected_errors => e
42
- raise ::Tradesman::Errors::Base.new(e.message)
43
- end
44
30
  end
@@ -51,7 +51,7 @@ describe Tradesman do
51
51
  after { Tradesman.reset }
52
52
 
53
53
  it 'throws error' do
54
- expect { Tradesman.adapter }.to raise_error(Tradesman::Errors::Base)
54
+ expect { Tradesman.adapter }.to raise_error(Tradesman::Base)
55
55
  end
56
56
  end
57
57
  end
@@ -90,10 +90,10 @@ describe Tradesman do
90
90
  end
91
91
  end
92
92
 
93
- context '#run' do
93
+ context '#go' do
94
94
  context 'Create' do
95
95
  context 'when parameters are valid' do
96
- let(:outcome) { Tradesman::CreateUser.run(last_name: 'Turner') }
96
+ let(:outcome) { Tradesman::CreateUser.go(last_name: 'Turner') }
97
97
 
98
98
  it 'creates a new record' do
99
99
  expect(outcome.success?).to be true
@@ -106,16 +106,47 @@ describe Tradesman do
106
106
  end
107
107
 
108
108
  context 'when parameters are invalid' do
109
- let(:outcome) { Tradesman::CreateStrictUser.run(first_name: 'Turner') }
109
+ let(:outcome) { Tradesman::CreateStrictUser.go(first_name: 'Turner') }
110
110
  it 'returns an invalid outcome' do
111
111
  expect(outcome.success?).to be false
112
112
  expect(outcome.type).to eq :validation
113
113
  end
114
114
  end
115
115
 
116
+ context 'multiple records' do
117
+ let(:outcome) { Tradesman::CreateStrictUser.go(param_list) }
118
+ context 'when all are valid' do
119
+ let(:param_list) { [{ last_name: 'Turner' }, { last_name: 'Smith' }, { last_name: 'Jones' }] }
120
+
121
+ it 'creates one record for each parameter set passed' do
122
+ expect(outcome.result.length).to eq param_list.length
123
+ outcome.result.each do |record|
124
+ expect(record.id.present?).to be true
125
+ end
126
+ end
127
+ end
128
+
129
+ context 'when one is valid' do
130
+ let(:param_list) { [{ first_name: 'Turner' }, { last_name: 'Smith' }, { age: 25 }] }
131
+
132
+ it 'creates invalid entities when params are invalid, valid entity otherwise' do
133
+ entities = outcome.result
134
+ expect(entities.length).to eq param_list.length
135
+
136
+ expect(entities.first.id).to be nil
137
+ expect(entities.first.valid?).to be false
138
+
139
+ expect(entities.second.id.is_a? Integer).to be true
140
+
141
+ expect(entities.third.id).to be nil
142
+ expect(entities.third.valid?).to be false
143
+ end
144
+ end
145
+ end
146
+
116
147
  context 'for parent' do
117
148
  let(:employer) { TradesmanSpec::Employer.create }
118
- let(:outcome) { Tradesman::CreateUserForEmployer.run(parent_id: employer.id, last_name: 'Turner') }
149
+ let(:outcome) { Tradesman::CreateUserForEmployer.go(employer.id, last_name: 'Turner') }
119
150
 
120
151
  it 'creates a new record' do
121
152
  expect(outcome.success?).to be true
@@ -130,6 +161,38 @@ describe Tradesman do
130
161
  outcome
131
162
  expect(employer.users.first.id).to eq outcome.result.id
132
163
  end
164
+
165
+ context 'multiple records' do
166
+ let(:employer) { Tradesman::CreateEmployer.go({}).result }
167
+ let(:outcome) { Tradesman::CreateStrictUserForEmployer.go(employer, param_list) }
168
+ context 'when all are valid' do
169
+ let(:param_list) { [{ last_name: 'Turner' }, { last_name: 'Smith' }, { last_name: 'Jones' }] }
170
+
171
+ it 'creates one record for each parameter set passed' do
172
+ expect(outcome.result.length).to eq param_list.length
173
+ outcome.result.each do |record|
174
+ expect(record.id.present?).to be true
175
+ end
176
+ end
177
+ end
178
+
179
+ context 'when one is valid' do
180
+ let(:param_list) { [{ first_name: 'Turner' }, { last_name: 'Smith' }, { age: 25 }] }
181
+
182
+ it 'creates invalid entities when params are invalid, valid entity otherwise' do
183
+ entities = outcome.result
184
+ expect(entities.length).to eq param_list.length
185
+
186
+ expect(entities.first.id).to be nil
187
+ expect(entities.first.valid?).to be false
188
+
189
+ expect(entities.second.id.is_a? Integer).to be true
190
+
191
+ expect(entities.third.id).to be nil
192
+ expect(entities.third.valid?).to be false
193
+ end
194
+ end
195
+ end
133
196
  end
134
197
  end
135
198
  end
@@ -137,7 +200,7 @@ describe Tradesman do
137
200
  context 'Update' do
138
201
  let(:user) { TradesmanSpec::User.create(last_name: 'Smith') }
139
202
  context 'when parameters are valid' do
140
- let(:outcome) { Tradesman::UpdateUser.run(id: user.id, last_name: 'Turner') }
203
+ let(:outcome) { Tradesman::UpdateUser.go(user.id, last_name: 'Turner') }
141
204
 
142
205
  it 'executes successfully' do
143
206
  expect(outcome.success?).to be true
@@ -151,19 +214,165 @@ describe Tradesman do
151
214
 
152
215
  context 'when parameters are invalid' do
153
216
  let(:strict_user) { TradesmanSpec::StrictUser.create(last_name: 'Smith') }
154
- let(:outcome) { Tradesman::UpdateStrictUser.run(id: strict_user.id, last_name: nil) }
217
+ let(:outcome) { Tradesman::UpdateStrictUser.go(strict_user, last_name: nil) }
218
+
219
+ it 'returns an invalid outcome' do
220
+ expect(outcome.success?).to be false
221
+ expect(outcome.type).to eq :validation
222
+ end
223
+ end
224
+
225
+ context 'when id is invalid' do
226
+ it 'throws error' do
227
+ expect { Tradesman::UpdateStrictUser.go('not_an_integer', last_name: nil) }.to raise_error Tradesman::InvalidId
228
+ end
229
+ end
230
+
231
+ context 'multiple records' do
232
+ let(:valid_params) { { last_name: 'Turner' } }
233
+ let(:outcome) { Tradesman::UpdateStrictUser.go(records, params) }
234
+
235
+ # Hash of id => params
236
+ # Tradesman::UpdateStrictUser.go(hash.keys, hash.values)
155
237
 
238
+ context 'passing array of ids and one valid parameter set' do
239
+ let(:records) { Tradesman::CreateStrictUser.go([valid_params, valid_params, valid_params]).result }
240
+ let(:params) { { last_name: 'Smith' } }
241
+
242
+ it 'creates one record for each parameter set passed' do
243
+ expect(outcome.result.length).to eq records.length
244
+ outcome.result.each do |record|
245
+ expect(record.last_name).to eq 'Smith'
246
+ expect(record.id.present?).to be true
247
+ end
248
+ end
249
+ end
250
+
251
+ context 'passing array of ids and multiple valid parameters' do
252
+ let(:records) { Tradesman::CreateStrictUser.go([valid_params, valid_params, valid_params]).result }
253
+ let(:params) { [{ last_name: 'Smith' }, { last_name: 'Williams' }, { last_name: 'Jones' }] }
254
+
255
+ it 'creates one record for each parameter set passed' do
256
+ results = outcome.result
257
+ expect(results.length).to eq records.length
258
+ expect(results.first.last_name).to eq params.first[:last_name]
259
+ expect(results.second.last_name).to eq params.second[:last_name]
260
+ expect(results.last.last_name).to eq params.last[:last_name]
261
+ end
262
+ end
263
+ end
264
+ end
265
+
266
+ context 'Delete' do
267
+ context 'when parameters are valid' do
268
+ let!(:user) { TradesmanSpec::User.create }
269
+ let(:outcome) { Tradesman::DeleteUser.go(user) }
270
+
271
+ it 'executes successfully' do
272
+ expect(outcome.success?).to be true
273
+ expect(outcome.result).to be true
274
+ end
275
+
276
+ it 'deletes record' do
277
+ expect { outcome }.to change(TradesmanSpec::User, :count).by(-1)
278
+ end
279
+ end
280
+
281
+ context 'when input parameters are invalid' do
282
+ let(:outcome) { Tradesman::DeleteUser.go(999) }
156
283
  it 'returns an invalid outcome' do
157
284
  expect(outcome.success?).to be false
158
285
  expect(outcome.type).to eq :validation
159
286
  end
160
287
  end
288
+
289
+ context 'multiple records' do
290
+ let(:valid_params) { { last_name: 'Turner' } }
291
+ let(:outcome) { Tradesman::DeleteStrictUser.go(records) }
292
+
293
+ context 'passing array of ids' do
294
+ let(:records) { Tradesman::CreateStrictUser.go([valid_params, valid_params, valid_params]).result }
295
+
296
+ it 'deletes all records' do
297
+ expect(outcome.result.length).to eq records.length
298
+ expect(outcome.result.uniq.first).to eq true
299
+ end
300
+ end
301
+ end
302
+ end
303
+
304
+ context '#go!' do
305
+ context 'Create' do
306
+ context 'when parameters are valid' do
307
+ let(:outcome) { Tradesman::CreateUser.go!(last_name: 'Turner') }
308
+
309
+ it 'creates a new record' do
310
+ expect(outcome.success?).to be true
311
+ expect(outcome.result.id.is_a? Integer).to be true
312
+ end
313
+
314
+ it 'returns Horza Entity' do
315
+ expect(outcome.result.is_a? Horza::Entities::Single).to be true
316
+ end
317
+ end
318
+
319
+ context 'when parameters are invalid' do
320
+ let(:outcome) { Tradesman::CreateStrictUser.go!({}) }
321
+ it 'throws error' do
322
+ expect { outcome }.to raise_error Tradesman::Invalid
323
+ end
324
+ end
325
+
326
+ context 'for parent' do
327
+ let(:employer) { TradesmanSpec::Employer.create }
328
+ let(:outcome) { Tradesman::CreateUserForEmployer.go!(employer.id, last_name: 'Turner') }
329
+
330
+ it 'creates a new record' do
331
+ expect(outcome.success?).to be true
332
+ expect(outcome.result.id.is_a? Integer).to be true
333
+ end
334
+
335
+ it 'associates child with parent' do
336
+ expect(outcome.result.employer_id).to eq employer.id
337
+ end
338
+
339
+ it 'associates parent with child' do
340
+ outcome
341
+ expect(employer.users.first.id).to eq outcome.result.id
342
+ end
343
+ end
344
+ end
345
+ end
346
+
347
+ context 'Update' do
348
+ let(:user) { TradesmanSpec::User.create(last_name: 'Smith') }
349
+ context 'when parameters are valid' do
350
+ let(:outcome) { Tradesman::UpdateUser.go!(user.id, last_name: 'Turner') }
351
+
352
+ it 'executes successfully' do
353
+ expect(outcome.success?).to be true
354
+ end
355
+
356
+ it 'updates record' do
357
+ expect(outcome.result.last_name).to eq 'Turner'
358
+ expect(user.reload.last_name).to eq 'Turner'
359
+ end
360
+ end
361
+
362
+ context 'when parameters are invalid' do
363
+ let(:strict_user) { TradesmanSpec::StrictUser.create(last_name: 'Smith') }
364
+ let(:outcome) { Tradesman::UpdateStrictUser.go!(strict_user, last_name: nil) }
365
+
366
+ it 'throws error' do
367
+ expect { outcome }.to raise_error Tradesman::Invalid
368
+ end
369
+ end
161
370
  end
162
371
 
163
372
  context 'Delete' do
164
373
  context 'when parameters are valid' do
165
374
  let!(:user) { TradesmanSpec::User.create }
166
- let(:outcome) { Tradesman::DeleteUser.run(id: user.id) }
375
+ let(:outcome) { Tradesman::DeleteUser.go!(user) }
167
376
 
168
377
  it 'executes successfully' do
169
378
  expect(outcome.success?).to be true
@@ -176,7 +385,7 @@ describe Tradesman do
176
385
  end
177
386
 
178
387
  context 'when input parameters are invalid' do
179
- let(:outcome) { Tradesman::DeleteUser.run(id: 999) }
388
+ let(:outcome) { Tradesman::DeleteUser.go(999) }
180
389
  it 'returns an invalid outcome' do
181
390
  expect(outcome.success?).to be false
182
391
  expect(outcome.type).to eq :validation
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tradesman
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Blake Turner
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-06-12 00:00:00.000000000 Z
12
+ date: 2015-06-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: horza
@@ -17,14 +17,14 @@ dependencies:
17
17
  requirements:
18
18
  - - "~>"
19
19
  - !ruby/object:Gem::Version
20
- version: 0.3.3
20
+ version: 0.3.5
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
25
  - - "~>"
26
26
  - !ruby/object:Gem::Version
27
- version: 0.3.3
27
+ version: 0.3.5
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: tzu
30
30
  requirement: !ruby/object:Gem::Requirement
@@ -138,10 +138,13 @@ files:
138
138
  - lib/tradesman/builders/create_for_parent.rb
139
139
  - lib/tradesman/builders/delete.rb
140
140
  - lib/tradesman/builders/update.rb
141
+ - lib/tradesman/class_methods.rb
141
142
  - lib/tradesman/configuration.rb
143
+ - lib/tradesman/error_handling.rb
142
144
  - lib/tradesman/errors.rb
145
+ - lib/tradesman/mixins/existing_records_multiple_execute.rb
146
+ - lib/tradesman/mixins/new_records_multiple_execute.rb
143
147
  - lib/tradesman/parser.rb
144
- - lib/tradesman/run_methods.rb
145
148
  - lib/tradesman/template.rb
146
149
  - spec/builders_spec.rb
147
150
  - spec/parser_spec.rb
@@ -1,11 +0,0 @@
1
- module Tradesman
2
- module RunMethods
3
- def run(*context)
4
- new(*context).run
5
- end
6
-
7
- def run!(*context)
8
- new(*context).run!
9
- end
10
- end
11
- end