traitr 0.0.4 → 0.0.5
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 +4 -4
- data/lib/traitor/config.rb +15 -3
- data/lib/traitor/helpers/active_record.rb +63 -0
- data/lib/traitor/helpers/rspec.rb +29 -0
- data/lib/traitor.rb +107 -105
- metadata +27 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 617169e1a6b866506fdb0e4804fe7d8e7eb22ad5
|
4
|
+
data.tar.gz: a54d3fa3d4ce4915eab40f90f89270efd2e7da23
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8fff94ed87623a0810bfd89ca3076dc8f2d3fd90cf21b284738d32a294dfe2cbd05f582b5fc143327f34ff90ec01bf82cd95e9fa7a00bbdfd1b697fc15240e4e
|
7
|
+
data.tar.gz: 5dfb5fb4b2af1e00372cddebdfec6b703364a9c20006d653a315d77e7ad6c3e5df8197df1b615ec9814a1b5b7da8b349df3a280bae0391147722fcc67aa80164
|
data/lib/traitor/config.rb
CHANGED
@@ -4,22 +4,21 @@ module Traitor
|
|
4
4
|
@create_kwargs = {}
|
5
5
|
@build_kwargs = {}
|
6
6
|
@build_with_list = false # use (**attributes.merge(build_kwargs)) instead of (attributes, **build_kwargs)
|
7
|
+
@no_callbacks = false
|
7
8
|
|
8
9
|
class << self
|
9
|
-
attr_accessor :create_method, :create_kwargs, :build_kwargs, :build_with_list
|
10
|
+
attr_accessor :create_method, :create_kwargs, :build_kwargs, :build_with_list, :no_callbacks
|
10
11
|
|
11
12
|
def configure_for_rails!
|
12
13
|
@create_method = :save
|
13
14
|
@create_kwargs = { validate: false }
|
14
15
|
@build_kwargs = { without_protection: true }
|
15
|
-
@build_with_list = false
|
16
16
|
end
|
17
17
|
|
18
18
|
def configure_safe_for_rails!
|
19
19
|
@create_method = :save
|
20
20
|
@create_kwargs = {}
|
21
21
|
@build_kwargs = {}
|
22
|
-
@build_with_list = false
|
23
22
|
end
|
24
23
|
|
25
24
|
def reset!
|
@@ -27,6 +26,19 @@ module Traitor
|
|
27
26
|
@create_kwargs = {}
|
28
27
|
@build_kwargs = {}
|
29
28
|
@build_with_list = false
|
29
|
+
@no_callbacks = false
|
30
|
+
end
|
31
|
+
|
32
|
+
def stash!
|
33
|
+
@old_config = Hash[
|
34
|
+
self.instance_variables.map { |att| [att, self.instance_variable_get(att)] }
|
35
|
+
]
|
36
|
+
end
|
37
|
+
|
38
|
+
def restore!
|
39
|
+
return unless @old_config
|
40
|
+
@old_config.each { |att, val| self.instance_variable_set(att, val) }
|
41
|
+
@old_config = nil
|
30
42
|
end
|
31
43
|
end
|
32
44
|
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# note that we do not have activerecord as a dependency in this gem!
|
2
|
+
# do not `require 'traitor/helpers/active_record'` unless you have ActiveRecord
|
3
|
+
# in your gemfile
|
4
|
+
|
5
|
+
require 'active_record'
|
6
|
+
|
7
|
+
module Traitor
|
8
|
+
module Helpers
|
9
|
+
module ActiveRecord
|
10
|
+
def create_without_callbacks
|
11
|
+
case self.class.connection.class.name
|
12
|
+
when 'ActiveRecord::ConnectionAdapters::PostgreSQLAdapter'
|
13
|
+
create_without_callbacks_pg
|
14
|
+
when 'ActiveRecord::ConnectionAdapters::SQLite3Adapter'
|
15
|
+
create_without_callbacks_sqlite
|
16
|
+
else
|
17
|
+
create_without_callbacks_default
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def create_without_callbacks_default
|
24
|
+
insert_sql = self.class.arel_table.create_insert.tap do |im|
|
25
|
+
im.insert(self.send(:arel_attributes_with_values_for_create, self.attribute_names))
|
26
|
+
end.to_sql
|
27
|
+
|
28
|
+
pk = self.class.primary_key
|
29
|
+
self.class.connection.execute(insert_sql)
|
30
|
+
id = self.maximum(pk)
|
31
|
+
self.send(:"#{pk}=", id)
|
32
|
+
self.clear_changes_information
|
33
|
+
end
|
34
|
+
|
35
|
+
def create_without_callbacks_sqlite
|
36
|
+
insert_sql = self.class.arel_table.create_insert.tap do |im|
|
37
|
+
im.insert(self.send(:arel_attributes_with_values_for_create, self.attribute_names))
|
38
|
+
end.to_sql
|
39
|
+
|
40
|
+
conn = self.class.connection
|
41
|
+
conn.execute(insert_sql)
|
42
|
+
|
43
|
+
pk = self.class.primary_key
|
44
|
+
id = conn.execute("SELECT last_insert_rowid() AS id")[0]['id']
|
45
|
+
self.send(:"#{pk}=", id)
|
46
|
+
self.clear_changes_information
|
47
|
+
end
|
48
|
+
|
49
|
+
def create_without_callbacks_pg
|
50
|
+
insert_sql = self.class.arel_table.create_insert.tap do |im|
|
51
|
+
im.insert(self.send(:arel_attributes_with_values_for_create, self.attribute_names))
|
52
|
+
end.to_sql
|
53
|
+
|
54
|
+
pk = self.class.primary_key
|
55
|
+
id = self.class.connection.execute(insert_sql + " RETURNING #{pk}")[0][pk]
|
56
|
+
self.send(:"#{pk}=", id)
|
57
|
+
self.clear_changes_information
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
ActiveRecord::Base.send :include, Traitor::Helpers::ActiveRecord
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
|
3
|
+
module Traitor
|
4
|
+
module Helpers
|
5
|
+
class RSpec
|
6
|
+
def self.configure!
|
7
|
+
::RSpec.configure do |config|
|
8
|
+
config.around(:example) do |example|
|
9
|
+
traitor_configs = example.metadata && example.metadata.select { |key, conf| key.to_s.start_with? 'traitor_' }
|
10
|
+
if traitor_configs && traitor_configs.any?
|
11
|
+
Traitor::Config.stash!
|
12
|
+
traitor_configs.each do |key, conf|
|
13
|
+
Traitor::Config.send(:"#{key.to_s.sub('traitor_', '')}=", conf)
|
14
|
+
end
|
15
|
+
|
16
|
+
example.run
|
17
|
+
|
18
|
+
Traitor::Config.restore!
|
19
|
+
else
|
20
|
+
example.run
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
Traitor::Helpers::RSpec.configure!
|
data/lib/traitor.rb
CHANGED
@@ -6,139 +6,141 @@ module Traitor
|
|
6
6
|
BLOCK_KEYS = [:after_build, :after_create]
|
7
7
|
|
8
8
|
@trait_library = {}
|
9
|
+
@alternate_create_methods = {}
|
9
10
|
@block_library = {}
|
10
11
|
@class_cache = {}
|
11
12
|
@trait_cache = {}
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
14
|
+
class << self
|
15
|
+
def reset!
|
16
|
+
@trait_library = {}
|
17
|
+
@alternate_create_methods = {}
|
18
|
+
@block_library = {}
|
19
|
+
@class_cache = {}
|
20
|
+
@trait_cache = {}
|
21
|
+
end
|
19
22
|
|
20
|
-
|
21
|
-
|
23
|
+
def define(klass, **traits)
|
24
|
+
@trait_library[klass] ||= {}
|
22
25
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
@block_library[klass][:class][block_type] = block
|
27
|
-
end
|
26
|
+
if alternate_create_method = traits.delete(:create_using)
|
27
|
+
@alternate_create_methods[klass] = [alternate_create_method, traits.delete(:create_using_kwargs) || {}]
|
28
|
+
end
|
28
29
|
|
29
|
-
|
30
|
-
|
31
|
-
block =
|
30
|
+
(traits.keys & BLOCK_KEYS).each do |block_type|
|
31
|
+
raise Traitor::Error.new("Callbacks are forbidden!") if Traitor::Config.no_callbacks
|
32
|
+
block = traits.delete block_type
|
32
33
|
@block_library[klass] ||= {class: {}, traits: {}}
|
33
|
-
@block_library[klass][:
|
34
|
-
@block_library[klass][:traits][trait][block_type] = block
|
34
|
+
@block_library[klass][:class][block_type] = block
|
35
35
|
end
|
36
|
-
end
|
37
36
|
|
38
|
-
|
39
|
-
|
37
|
+
traits.each do |trait, attributes|
|
38
|
+
(attributes.keys & BLOCK_KEYS).each do |block_type|
|
39
|
+
raise Traitor::Error.new("Callbacks are forbidden!") if Traitor::Config.no_callbacks
|
40
|
+
block = attributes.delete block_type
|
41
|
+
@block_library[klass] ||= {class: {}, traits: {}}
|
42
|
+
@block_library[klass][:traits][trait] ||= {}
|
43
|
+
@block_library[klass][:traits][trait][block_type] = block
|
44
|
+
end
|
45
|
+
end
|
40
46
|
|
41
|
-
|
42
|
-
|
43
|
-
# and then save it.
|
44
|
-
##
|
45
|
-
def self.create(klass, *traits, **attributes)
|
46
|
-
create_method = Traitor::Config.create_method
|
47
|
-
raise Traitor::Error.new("Cannot call Traitor.create until you have configured Traitor.create_method .") unless create_method
|
47
|
+
@trait_library[klass].merge!(traits)
|
48
|
+
end
|
48
49
|
|
49
|
-
|
50
|
+
##
|
51
|
+
# build an instance of an object using the defined traits and attributes.
|
52
|
+
##
|
53
|
+
def build(klass, *traits, **attributes)
|
54
|
+
attributes = get_attributes_from_traits(klass, traits).merge(attributes)
|
55
|
+
build_kwargs = Traitor::Config.build_kwargs || {}
|
56
|
+
|
57
|
+
record = if Traitor::Config.build_with_list
|
58
|
+
convert_to_class(klass).new(**attributes.merge(build_kwargs))
|
59
|
+
elsif build_kwargs.any?
|
60
|
+
convert_to_class(klass).new(attributes, **build_kwargs)
|
61
|
+
else
|
62
|
+
convert_to_class(klass).new(attributes)
|
63
|
+
end
|
50
64
|
|
51
|
-
|
52
|
-
record
|
53
|
-
else
|
54
|
-
record.public_send(create_method)
|
65
|
+
call_blocks(klass, :after_build, record, *traits)
|
66
|
+
record
|
55
67
|
end
|
56
68
|
|
57
|
-
|
58
|
-
|
59
|
-
|
69
|
+
##
|
70
|
+
# build an instance of an object using the defined traits and attributes,
|
71
|
+
# and then save it.
|
72
|
+
##
|
73
|
+
def create(klass, *traits, **attributes)
|
74
|
+
create_method, create_kwargs = @alternate_create_methods[klass] ||
|
75
|
+
[Traitor::Config.create_method, Traitor::Config.create_kwargs || {}]
|
60
76
|
|
61
|
-
|
62
|
-
# build an instance of an object using the defined traits and attributes.
|
63
|
-
##
|
64
|
-
def self.build(klass, *traits, **attributes)
|
65
|
-
attributes = get_attributes_from_traits(klass, traits).merge(attributes)
|
66
|
-
build_kwargs = Traitor::Config.build_kwargs
|
67
|
-
|
68
|
-
record = if Traitor::Config.build_with_list
|
69
|
-
convert_to_class(klass).new(**attributes.merge(build_kwargs))
|
70
|
-
elsif build_kwargs.any?
|
71
|
-
convert_to_class(klass).new(attributes, **build_kwargs)
|
72
|
-
else
|
73
|
-
convert_to_class(klass).new(attributes)
|
74
|
-
end
|
77
|
+
raise Traitor::Error.new("Cannot call Traitor.create until you have configured Traitor.create_method .") unless create_method
|
75
78
|
|
76
|
-
|
77
|
-
record
|
78
|
-
end
|
79
|
+
record = build(klass, *traits, **attributes)
|
79
80
|
|
80
|
-
|
81
|
-
|
82
|
-
|
81
|
+
if create_kwargs.any? # assignment intentional
|
82
|
+
record.public_send(create_method, **create_kwargs)
|
83
|
+
else
|
84
|
+
record.public_send(create_method)
|
85
|
+
end
|
83
86
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
+
call_blocks(klass, :after_create, record, *traits)
|
88
|
+
record
|
89
|
+
end
|
87
90
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
91
|
+
def create_using(klass, create_method, *traits, **attributes)
|
92
|
+
old_create_method_kwargs = @alternate_create_methods[klass]
|
93
|
+
@alternate_create_methods[klass] = [create_method, attributes.delete(:create_kwargs) || {}]
|
94
|
+
create(klass, *traits, **attributes)
|
95
|
+
ensure
|
96
|
+
@alternate_create_methods[klass] = old_create_method_kwargs
|
97
|
+
end
|
93
98
|
|
94
|
-
|
99
|
+
private
|
95
100
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
101
|
+
def call_blocks(klass, trigger, record, *traits)
|
102
|
+
return unless @block_library[klass]
|
103
|
+
[].tap do |blocks|
|
104
|
+
blocks << @block_library[klass][:class][trigger]
|
105
|
+
traits.each do |trait|
|
106
|
+
if @block_library[klass][:traits][trait]
|
107
|
+
blocks << @block_library[klass][:traits][trait][trigger]
|
108
|
+
end
|
103
109
|
end
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
107
|
-
private_class_method :call_blocks
|
110
|
+
end.compact.each { |block| block.call(record) }
|
111
|
+
end
|
108
112
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
113
|
+
def convert_to_class(klass)
|
114
|
+
@class_cache[klass] ||= Object.const_get(camelize(klass))
|
115
|
+
rescue NameError
|
116
|
+
raise Traitor::Error.new("Tried to create a #{camelize(klass)}, but it does not exist!")
|
117
|
+
end
|
118
|
+
|
119
|
+
def get_attributes_from_traits(klass, traits)
|
120
|
+
# we only call this method when the klass has been converted to a key inside create
|
121
|
+
return {} unless library = @trait_library[klass]
|
115
122
|
|
116
|
-
|
117
|
-
# we only call this method when the klass has been converted to a key inside create
|
118
|
-
return {} unless library = @trait_library[klass]
|
123
|
+
traits = [:default_traits] + traits # always include default_traits as the first thing
|
119
124
|
|
120
|
-
|
125
|
+
cache_key = klass.to_s + ':' + traits.join(':')
|
126
|
+
@trait_cache[cache_key] ||= {}.tap do |attributes|
|
127
|
+
traits.each { |trait| attributes.merge!(library[trait] || {}) }
|
128
|
+
end
|
121
129
|
|
122
|
-
|
123
|
-
|
124
|
-
|
130
|
+
# use late resolution on lambda values by calling them here as part of constructing a new hash
|
131
|
+
Hash[
|
132
|
+
@trait_cache[cache_key].map do |attribute, value|
|
133
|
+
[attribute, value.is_a?(Proc) && ![:after_build, :after_create].include?(attribute) ? value.call : value]
|
134
|
+
end
|
135
|
+
]
|
125
136
|
end
|
126
137
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
private_class_method :get_attributes_from_traits
|
135
|
-
|
136
|
-
def self.camelize(term)
|
137
|
-
string = term.to_s
|
138
|
-
string[0] = string[0].upcase
|
139
|
-
string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{$2.capitalize}" }
|
140
|
-
string.gsub!('/'.freeze, '::'.freeze)
|
141
|
-
string
|
138
|
+
def camelize(term)
|
139
|
+
string = term.to_s
|
140
|
+
string[0] = string[0].upcase
|
141
|
+
string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{$2.capitalize}" }
|
142
|
+
string.gsub!('/'.freeze, '::'.freeze)
|
143
|
+
string
|
144
|
+
end
|
142
145
|
end
|
143
|
-
private_class_method :camelize
|
144
146
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: traitr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Zach Lome
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-07-
|
11
|
+
date: 2016-07-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -25,35 +25,35 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: rspec
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
33
|
+
version: '3.0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
40
|
+
version: '3.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name: rspec
|
42
|
+
name: rspec-its
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
47
|
+
version: '1.0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
54
|
+
version: '1.0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: timecop
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - ">="
|
@@ -67,7 +67,7 @@ dependencies:
|
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: pry
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - ">="
|
@@ -81,7 +81,7 @@ dependencies:
|
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
84
|
+
name: sqlite3
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - ">="
|
@@ -94,6 +94,20 @@ dependencies:
|
|
94
94
|
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: activerecord
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '4'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '4'
|
97
111
|
description: a lightweight, simplified, pure-ruby way to handle object model construction,
|
98
112
|
similar to FactoryGirl.
|
99
113
|
email:
|
@@ -106,6 +120,8 @@ files:
|
|
106
120
|
- lib/traitor/config.rb
|
107
121
|
- lib/traitor/error.rb
|
108
122
|
- lib/traitor/find_definitions.rb
|
123
|
+
- lib/traitor/helpers/active_record.rb
|
124
|
+
- lib/traitor/helpers/rspec.rb
|
109
125
|
homepage: https://github.com/kuraiou/traitor
|
110
126
|
licenses:
|
111
127
|
- MIT
|