tradesman 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c3709e7f3b27cda92aaf6dc131eaf6aa1b3de869
4
+ data.tar.gz: 9862de5df502cccce9682806e1710df738f4bde1
5
+ SHA512:
6
+ metadata.gz: c1219785e7c94d998ba219a11764daf8df4d76d1073e43ba0a73ee9f31b40df982f90e15d602ebdb53f7ac7fbdd805331207765074549fdde8c9e0817d0f5da2
7
+ data.tar.gz: 56650c880247e12f10b6638bfab459bbddd5cbcc1c5c6d533235221175d7aa27c1ee2059f185d49dbe4bcddae3b1b26cc7aa9ab6a6bea1514a653cb63e0b56fb
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2015 Blake Turner
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,85 @@
1
+ # Tradesman
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.
6
+
7
+ ## Usage
8
+
9
+ ```ruby
10
+ # Simple - Returns an Outcome
11
+ outcome = Tradesman::CreateUser.run(user_params)
12
+ outcome.success? #=> true
13
+ outcome.result #=> User Entity
14
+
15
+ # Passing a block - Well-suited for Controllers
16
+ Tradesman::UpdateUser.run(params[:id], user_update_params) do
17
+ success do |result|
18
+ render(text: 'true', status: 200)
19
+ end
20
+
21
+ invalid do |error|
22
+ render(text: 'false', status: 404)
23
+ end
24
+
25
+ failure do |result|
26
+ render(text: 'false', status: 400)
27
+ end
28
+ end
29
+
30
+ # Can also Delete
31
+ Tradesman::DeleteUser.run(params[:id])
32
+
33
+ # Or Create as a child of an existing record
34
+ Tradesman::CreateUserForEmployer.run(employer_id, user_params)
35
+ ```
36
+
37
+ ## Why is this necessary?
38
+
39
+ 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:
40
+
41
+ - Query existing record by some group of parameters, but generally just by :id (Update and Delete only)
42
+ - Return 404 if record does not exist
43
+ - Update or Create a new record with a given set of parameters. For Deletion, no parameters are required.
44
+ - Return a success, invalid, or failure message based on the result of this persistence action.
45
+
46
+ Example:
47
+ ```ruby
48
+ # users_controller.rb
49
+ def update
50
+ @user = User.find(params[:id])
51
+ return render(text: 'false', status: 404) unless @user
52
+
53
+ @user.assign_attributes(user_params)
54
+ return render(text: 'false', status: 400) unless @user.save
55
+
56
+ render 'user'
57
+ end
58
+
59
+ private
60
+
61
+ def user_params
62
+ params.permit(:first_name, :last_name, :email)
63
+ end
64
+ ```
65
+
66
+ Yes, the above example is trivial, but many such trivial actions are necessary in web applications.
67
+ Tradesman is designed to handle the above and a few other common use-cases to reduce such tedious, often-repeated boilerplate code.
68
+
69
+ Tradesman version of the above:
70
+ ```ruby
71
+ Tradesman::UpdateUser.run(params[:id], user_params) do
72
+ success do |result|
73
+ @user = result
74
+ render 'user'
75
+ end
76
+
77
+ invalid do |error|
78
+ render(text: 'false', status: 404)
79
+ end
80
+
81
+ failure { |result| render(text: 'false', status: 400) } # If you prefer one-liners
82
+ end
83
+ ```
84
+
85
+ The Tradesman version says exactly what it does, is cruft free, and is much quicker to test (more on that later).
@@ -0,0 +1,24 @@
1
+ module Tradesman
2
+ module Builders
3
+ class Base
4
+ def initialize(class_name)
5
+ parser = ::Tradesman::Parser.new(class_name)
6
+ @subject = parser.subject
7
+ @parent = parser.parent
8
+ end
9
+
10
+ def class
11
+ template_class(class_args)
12
+ end
13
+
14
+ private
15
+
16
+ def class_args
17
+ {
18
+ subject: @subject,
19
+ parent: @parent
20
+ }
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,19 @@
1
+ module Tradesman
2
+ module Builders
3
+ class Create < Base
4
+ private
5
+
6
+ def template_class(args)
7
+ Class.new(::Tradesman::Template) do
8
+ @store = Tradesman.adapter.context_for_entity(args[:subject])
9
+
10
+ private
11
+
12
+ def execute(params)
13
+ self.class.adapter.create!(params)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,34 @@
1
+ module Tradesman
2
+ module Builders
3
+ class CreateForParent < Base
4
+ private
5
+
6
+ def template_class(args)
7
+ Class.new(::Tradesman::Template) do
8
+ @store = Tradesman.adapter.context_for_entity(args[:subject])
9
+ @parent_store = Tradesman.adapter.context_for_entity(args[:parent])
10
+ @parent_key = args[:parent]
11
+
12
+ class << self
13
+ attr_reader :parent_store, :parent_key
14
+
15
+ def parent_adapter
16
+ Tradesman.adapter.new(parent_store)
17
+ end
18
+ end
19
+
20
+ private
21
+
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))
25
+ end
26
+
27
+ def relation_id
28
+ "#{self.class.parent_key}_id"
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,19 @@
1
+ module Tradesman
2
+ module Builders
3
+ class Delete < Base
4
+ private
5
+
6
+ def template_class(args)
7
+ Class.new(::Tradesman::Template) do
8
+ @store = Tradesman.adapter.context_for_entity(args[:subject])
9
+
10
+ private
11
+
12
+ def execute(params)
13
+ self.class.adapter.delete!(params[:id])
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ module Tradesman
2
+ module Builders
3
+ class Update < Base
4
+ private
5
+
6
+ def template_class(args)
7
+ Class.new(::Tradesman::Template) do
8
+ @store = Tradesman.adapter.context_for_entity(args[:subject])
9
+
10
+ private
11
+
12
+ def execute(params)
13
+ self.class.adapter.update!(params[:id], params.except(:id))
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,20 @@
1
+ module Tradesman
2
+ module Builders
3
+ class << self
4
+ def generate_class(parser)
5
+ Tradesman.const_set(parser.class_name, builder_for_action(parser.action, parser.parent).new(parser.class_name).class)
6
+ end
7
+
8
+ def builder_for_action(action, parent)
9
+ case action
10
+ when :create
11
+ parent ? CreateForParent : Create
12
+ when :update
13
+ Update
14
+ when :delete
15
+ Delete
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,30 @@
1
+ module Tradesman
2
+ module Configuration
3
+ def configuration
4
+ @configuration ||= Config.new
5
+ end
6
+
7
+ def reset
8
+ @configuration = Config.new
9
+ @adapter, @adapter_map = nil, nil # Class-level cache clear
10
+ end
11
+
12
+ def configure
13
+ yield(configuration)
14
+ end
15
+
16
+ def adapter
17
+ raise ::Tradesman::Errors::Base.new('Adapter has not been configured') unless configuration.adapter
18
+ @adapter ||= configuration.adapter
19
+ end
20
+ end
21
+
22
+ class Config
23
+ attr_accessor :adapter
24
+
25
+ def set_adapter(adapter)
26
+ Horza.configure { |config| config.adapter = adapter }
27
+ @adapter = Horza.adapter
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,12 @@
1
+ module Tradesman
2
+ module Errors
3
+ class Base < StandardError
4
+ end
5
+
6
+ class MethodNotImplemented < StandardError
7
+ end
8
+
9
+ class RecordNotFound < StandardError
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,41 @@
1
+ module Tradesman
2
+ class Parser
3
+ attr_reader :class_name, :action_string, :subject_string, :parent_string
4
+
5
+ PARSE_REGEX = /(Create|Update|Delete)(.+)/
6
+ PARSE_REGEX_WITH_PARENT = /(Create|Update|Delete)(.+)4(.+)/
7
+
8
+ def initialize(class_name)
9
+ @class_name = class_name
10
+ @match = class_name.to_s.match(regex)
11
+ @action_string, @subject_string, @parent_string = @match.values_at(1, 2, 3) if @match
12
+ end
13
+
14
+ def match?
15
+ !!@match
16
+ end
17
+
18
+ def action
19
+ str_to_sym(@action_string)
20
+ end
21
+
22
+ def subject
23
+ str_to_sym(@subject_string)
24
+ end
25
+
26
+ def parent
27
+ return nil unless @parent_string
28
+ str_to_sym(@parent_string)
29
+ end
30
+
31
+ private
32
+
33
+ def regex
34
+ /.+4.+/.match(@class_name) ? PARSE_REGEX_WITH_PARENT : PARSE_REGEX
35
+ end
36
+
37
+ def str_to_sym(str)
38
+ str.underscore.symbolize
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,11 @@
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
@@ -0,0 +1,26 @@
1
+ module Tradesman
2
+ class Template
3
+ include ::Tzu
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
13
+
14
+ def call(params)
15
+ execute(params)
16
+ rescue Horza::Errors::RecordInvalid, Horza::Errors::RecordNotFound => e
17
+ invalid! e
18
+ end
19
+
20
+ private
21
+
22
+ def execute(params)
23
+ raise Tradesman::Errors::MethodNotImplemented.new
24
+ end
25
+ end
26
+ end
data/lib/tradesman.rb ADDED
@@ -0,0 +1,44 @@
1
+ require 'horza'
2
+ require 'tzu'
3
+ require 'tradesman/builders'
4
+ require 'tradesman/builders/base'
5
+ require 'tradesman/builders/create'
6
+ require 'tradesman/builders/create_for_parent'
7
+ require 'tradesman/builders/delete'
8
+ require 'tradesman/builders/update'
9
+ require 'tradesman/configuration'
10
+ require 'tradesman/errors'
11
+ require 'tradesman/parser'
12
+ require 'tradesman/run_methods'
13
+ require 'tradesman/template'
14
+
15
+ module Tradesman
16
+ extend Tradesman::Configuration
17
+
18
+ class << self
19
+ attr_writer :configuration
20
+
21
+ def included(base)
22
+ base.class_eval do
23
+ extend ::Tradesman::RunMethods
24
+ end
25
+ end
26
+
27
+ def const_missing(class_name)
28
+ parser = ::Tradesman::Parser.new(class_name)
29
+ return super(class_name) unless parser.match?
30
+ Builders.generate_class(parser)
31
+ end
32
+ 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
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe Tradesman::Builders do
4
+ context '#builder_for_action' do
5
+ context 'Create' do
6
+ it 'returns Create class' do
7
+ expect(Tradesman::Builders.builder_for_action(:create, nil)).to eq Tradesman::Builders::Create
8
+ end
9
+ end
10
+
11
+ context 'Create with Parent' do
12
+ it 'returns Create class' do
13
+ expect(Tradesman::Builders.builder_for_action(:create, :user)).to eq Tradesman::Builders::CreateForParent
14
+ end
15
+ end
16
+
17
+ context 'Update' do
18
+ it 'returns Create class' do
19
+ expect(Tradesman::Builders.builder_for_action(:update, nil)).to eq Tradesman::Builders::Update
20
+ end
21
+ end
22
+
23
+ context 'Delete' do
24
+ it 'returns Create class' do
25
+ expect(Tradesman::Builders.builder_for_action(:delete, nil)).to eq Tradesman::Builders::Delete
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,74 @@
1
+ require 'spec_helper'
2
+
3
+ describe Tradesman::Parser do
4
+ context 'when pattern is valid' do
5
+ context 'CreateUser' do
6
+ subject { Tradesman::Parser.new('CreateUser') }
7
+
8
+ it 'finds a match' do
9
+ expect(subject.match?).to be true
10
+ end
11
+
12
+ it 'parses the action' do
13
+ expect(subject.action).to eq :create
14
+ end
15
+
16
+ it 'parses the subject' do
17
+ expect(subject.subject).to eq :user
18
+ end
19
+ end
20
+
21
+ context 'CreateUser4Employer' do
22
+ subject { Tradesman::Parser.new('CreateUser4Employer') }
23
+
24
+ it 'finds a match' do
25
+ expect(subject.match?).to be true
26
+ end
27
+
28
+ it 'parses the action' do
29
+ expect(subject.action).to eq :create
30
+ end
31
+
32
+ it 'parses the subject' do
33
+ expect(subject.subject).to eq :user
34
+ end
35
+
36
+ it 'parses the parent' do
37
+ expect(subject.parent).to eq :employer
38
+ end
39
+ end
40
+
41
+ context 'DeleteCustomerInvoice' do
42
+ subject { Tradesman::Parser.new('DeleteCustomerInvoice') }
43
+
44
+ it 'finds a match' do
45
+ expect(subject.match?).to be true
46
+ end
47
+
48
+ it 'parses the action' do
49
+ expect(subject.action).to eq :delete
50
+ end
51
+
52
+ it 'parses the subject' do
53
+ expect(subject.subject).to eq :customer_invoice
54
+ end
55
+ end
56
+
57
+ context 'UpdateTransaction' do
58
+ subject { Tradesman::Parser.new('UpdateTransaction') }
59
+
60
+ it 'finds a match' do
61
+ expect(subject.match?).to be true
62
+ end
63
+
64
+ it 'parses the action' do
65
+ expect(subject.action).to eq :update
66
+ end
67
+
68
+ it 'parses the subject' do
69
+ expect(subject.subject).to eq :transaction
70
+ end
71
+ end
72
+ end
73
+
74
+ end
@@ -0,0 +1,8 @@
1
+ require 'rubygems'
2
+ require 'byebug'
3
+ require 'rspec'
4
+ require 'active_record'
5
+ require 'bundler/setup'
6
+ Bundler.setup
7
+
8
+ require 'tradesman'
@@ -0,0 +1,152 @@
1
+ require 'spec_helper'
2
+
3
+ if !defined?(ActiveRecord::Base)
4
+ puts "** require 'active_record' to run the specs in #{__FILE__}"
5
+ else
6
+ ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
7
+
8
+ ActiveRecord::Migration.suppress_messages do
9
+ ActiveRecord::Schema.define(:version => 0) do
10
+ create_table(:employers, force: true) {|t| t.string :name }
11
+ create_table(:users, force: true) {|t| t.string :first_name; t.string :last_name; t.references :employer; }
12
+ create_table(:strict_users, force: true) {|t| t.string :first_name; t.string :last_name; t.references :employer; }
13
+ end
14
+ end
15
+
16
+ module TradesmanSpec
17
+ class Employer < ActiveRecord::Base
18
+ has_many :users
19
+ end
20
+
21
+ class User < ActiveRecord::Base
22
+ belongs_to :employer
23
+ end
24
+
25
+ class StrictUser < ActiveRecord::Base
26
+ belongs_to :employer
27
+
28
+ validates :last_name, presence: true
29
+ end
30
+ end
31
+ end
32
+
33
+ describe Tradesman do
34
+ let(:adapter) { :active_record }
35
+ before { Tradesman.configure { |config| config.set_adapter(adapter) } }
36
+ after do
37
+ TradesmanSpec::User.delete_all
38
+ TradesmanSpec::StrictUser.delete_all
39
+ TradesmanSpec::Employer.delete_all
40
+ end
41
+
42
+ context '#configure' do
43
+ context 'when the adapter is set' do
44
+ it 'returns the correct adapter class' do
45
+ expect(Tradesman.adapter).to eq Horza::Adapters::ActiveRecord
46
+ end
47
+ end
48
+
49
+ context 'when the adapter is not set' do
50
+ before { Tradesman.reset }
51
+ after { Tradesman.reset }
52
+
53
+ it 'throws error' do
54
+ expect { Tradesman.adapter }.to raise_error(Tradesman::Errors::Base)
55
+ end
56
+ end
57
+ end
58
+
59
+ context '#run' do
60
+ context 'Create' do
61
+ context 'when parameters are valid' do
62
+ let(:outcome) { Tradesman::CreateUser.run(last_name: 'Turner') }
63
+
64
+ it 'creates a new record' do
65
+ expect(outcome.success?).to be true
66
+ expect(outcome.result.id.is_a? Integer).to be true
67
+ end
68
+
69
+ it 'returns Horza Entity' do
70
+ expect(outcome.result.is_a? Horza::Entities::Single).to be true
71
+ end
72
+ end
73
+
74
+ context 'when parameters are invalid' do
75
+ let(:outcome) { Tradesman::CreateStrictUser.run(first_name: 'Turner') }
76
+ it 'returns an invalid outcome' do
77
+ expect(outcome.success?).to be false
78
+ expect(outcome.type).to eq :validation
79
+ end
80
+ end
81
+
82
+ context 'for parent' do
83
+ let(:employer) { TradesmanSpec::Employer.create }
84
+ let(:outcome) { Tradesman::CreateUser4Employer.run(parent_id: employer.id, last_name: 'Turner') }
85
+
86
+ it 'creates a new record' do
87
+ expect(outcome.success?).to be true
88
+ expect(outcome.result.id.is_a? Integer).to be true
89
+ end
90
+
91
+ it 'associates child with parent' do
92
+ expect(outcome.result.employer_id).to eq employer.id
93
+ end
94
+
95
+ it 'associates parent with child' do
96
+ outcome
97
+ expect(employer.users.first.id).to eq outcome.result.id
98
+ end
99
+ end
100
+ end
101
+ end
102
+
103
+ context 'Update' do
104
+ let(:user) { TradesmanSpec::User.create(last_name: 'Smith') }
105
+ context 'when parameters are valid' do
106
+ let(:outcome) { Tradesman::UpdateUser.run(id: user.id, last_name: 'Turner') }
107
+
108
+ it 'executes successfully' do
109
+ expect(outcome.success?).to be true
110
+ end
111
+
112
+ it 'updates record' do
113
+ expect(outcome.result.last_name).to eq 'Turner'
114
+ expect(user.reload.last_name).to eq 'Turner'
115
+ end
116
+ end
117
+
118
+ context 'when parameters are invalid' do
119
+ let(:strict_user) { TradesmanSpec::StrictUser.create(last_name: 'Smith') }
120
+ let(:outcome) { Tradesman::UpdateStrictUser.run(id: strict_user.id, last_name: nil) }
121
+
122
+ it 'returns an invalid outcome' do
123
+ expect(outcome.success?).to be false
124
+ expect(outcome.type).to eq :validation
125
+ end
126
+ end
127
+ end
128
+
129
+ context 'Delete' do
130
+ context 'when parameters are valid' do
131
+ let!(:user) { TradesmanSpec::User.create }
132
+ let(:outcome) { Tradesman::DeleteUser.run(id: user.id) }
133
+
134
+ it 'executes successfully' do
135
+ expect(outcome.success?).to be true
136
+ expect(outcome.result).to be true
137
+ end
138
+
139
+ it 'deletes record' do
140
+ expect { outcome }.to change(TradesmanSpec::User, :count).by(-1)
141
+ end
142
+ end
143
+
144
+ context 'when input parameters are invalid' do
145
+ let(:outcome) { Tradesman::DeleteUser.run(id: 999) }
146
+ it 'returns an invalid outcome' do
147
+ expect(outcome.success?).to be false
148
+ expect(outcome.type).to eq :validation
149
+ end
150
+ end
151
+ end
152
+ end
metadata ADDED
@@ -0,0 +1,180 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tradesman
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Blake Turner
8
+ - Morgan Bruce
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2015-05-28 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: horza
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - '='
19
+ - !ruby/object:Gem::Version
20
+ version: 0.2.0
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - '='
26
+ - !ruby/object:Gem::Version
27
+ version: 0.2.0
28
+ - !ruby/object:Gem::Dependency
29
+ name: tzu
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - '='
33
+ - !ruby/object:Gem::Version
34
+ version: 0.0.1.0
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - '='
40
+ - !ruby/object:Gem::Version
41
+ version: 0.0.1.0
42
+ - !ruby/object:Gem::Dependency
43
+ name: bundler
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: 1.0.0
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: 1.0.0
56
+ - !ruby/object:Gem::Dependency
57
+ name: activerecord
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: 3.2.15
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: 3.2.15
70
+ - !ruby/object:Gem::Dependency
71
+ name: activesupport
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: 3.2.15
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: 3.2.15
84
+ - !ruby/object:Gem::Dependency
85
+ name: rspec
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: 2.4.0
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: 2.4.0
98
+ - !ruby/object:Gem::Dependency
99
+ name: sqlite3
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ - !ruby/object:Gem::Dependency
113
+ name: byebug
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ description: Encapsulate common application behaviour with dynamically generated classes
127
+ email: mail@blakewilliamturner.com
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - LICENSE.txt
133
+ - README.md
134
+ - lib/tradesman.rb
135
+ - lib/tradesman/builders.rb
136
+ - lib/tradesman/builders/base.rb
137
+ - lib/tradesman/builders/create.rb
138
+ - lib/tradesman/builders/create_for_parent.rb
139
+ - lib/tradesman/builders/delete.rb
140
+ - lib/tradesman/builders/update.rb
141
+ - lib/tradesman/configuration.rb
142
+ - lib/tradesman/errors.rb
143
+ - lib/tradesman/parser.rb
144
+ - lib/tradesman/run_methods.rb
145
+ - lib/tradesman/template.rb
146
+ - spec/builders_spec.rb
147
+ - spec/parser_spec.rb
148
+ - spec/spec_helper.rb
149
+ - spec/tradesman_spec.rb
150
+ homepage: https://github.com/onfido/tradesman
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.2.2
171
+ signing_key:
172
+ specification_version: 4
173
+ summary: Tradesman dynamically generates classes with human-readble names that handle
174
+ the pass, fail, and invalid results of common create, update, and delete actions.
175
+ test_files:
176
+ - spec/builders_spec.rb
177
+ - spec/parser_spec.rb
178
+ - spec/spec_helper.rb
179
+ - spec/tradesman_spec.rb
180
+ has_rdoc: