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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 020595fcb015240ac313662cc5e284f10ee4ab06
4
- data.tar.gz: 798775cefb913fc437972b29e8e412b792b29d9c
3
+ metadata.gz: 617169e1a6b866506fdb0e4804fe7d8e7eb22ad5
4
+ data.tar.gz: a54d3fa3d4ce4915eab40f90f89270efd2e7da23
5
5
  SHA512:
6
- metadata.gz: 7c8371264c2dcc1ce8b3cf7af4e057567c6b69e765e2e14279b420631f94b0de1ddc01e46623f50901e3700616563aba45d72d61a99eaa3911adc8ff959e1b56
7
- data.tar.gz: 0b71b50fe8da6da863269c9f6db7d82770a55ec6a1949f0b67eb4ce9a9f477058c6a0b73e6f5150ff2d14962ec3a57bdb72c67c456b720036f8a0b23ae915638
6
+ metadata.gz: 8fff94ed87623a0810bfd89ca3076dc8f2d3fd90cf21b284738d32a294dfe2cbd05f582b5fc143327f34ff90ec01bf82cd95e9fa7a00bbdfd1b697fc15240e4e
7
+ data.tar.gz: 5dfb5fb4b2af1e00372cddebdfec6b703364a9c20006d653a315d77e7ad6c3e5df8197df1b615ec9814a1b5b7da8b349df3a280bae0391147722fcc67aa80164
@@ -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
- def self.reset!
14
- @trait_library = {}
15
- @block_library = {}
16
- @class_cache = {}
17
- @trait_cache = {}
18
- end
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
- def self.define(klass, **traits)
21
- @trait_library[klass] ||= {}
23
+ def define(klass, **traits)
24
+ @trait_library[klass] ||= {}
22
25
 
23
- (traits.keys & BLOCK_KEYS).each do |block_type|
24
- block = traits.delete block_type
25
- @block_library[klass] ||= {class: {}, traits: {}}
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
- traits.each do |trait, attributes|
30
- (attributes.keys & BLOCK_KEYS).each do |block_type|
31
- block = attributes.delete block_type
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][:traits][trait] ||= {}
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
- @trait_library[klass].merge!(traits)
39
- end
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
- # build an instance of an object using the defined traits and attributes,
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
- record = build(klass, *traits, **attributes)
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
- if (create_kwargs = Traitor::Config.create_kwargs).any? # assignment intentional
52
- record.public_send(create_method, **create_kwargs)
53
- else
54
- record.public_send(create_method)
65
+ call_blocks(klass, :after_build, record, *traits)
66
+ record
55
67
  end
56
68
 
57
- call_blocks(klass, :after_create, record, *traits)
58
- record
59
- end
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
- call_blocks(klass, :after_build, record, *traits)
77
- record
78
- end
79
+ record = build(klass, *traits, **attributes)
79
80
 
80
- def self.create_using(klass, create_method, *traits, **attributes)
81
- old_create_method = Traitor::Config.create_method
82
- old_create_kwargs = Traitor::Config.create_kwargs
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
- new_create_kwargs = attributes.delete :create_kwargs
85
- Traitor::Config.create_method = create_method
86
- Traitor::Config.create_kwargs = new_create_kwargs if new_create_kwargs
87
+ call_blocks(klass, :after_create, record, *traits)
88
+ record
89
+ end
87
90
 
88
- create(klass, *traits, **attributes)
89
- ensure
90
- Traitor::Config.create_method = old_create_method
91
- Traitor::Config.create_kwargs = old_create_kwargs
92
- end
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
- # private methods
99
+ private
95
100
 
96
- def self.call_blocks(klass, trigger, record, *traits)
97
- return unless @block_library[klass]
98
- [].tap do |blocks|
99
- blocks << @block_library[klass][:class][trigger]
100
- traits.each do |trait|
101
- if @block_library[klass][:traits][trait]
102
- blocks << @block_library[klass][:traits][trait][trigger]
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.compact.each { |block| block.call(record) }
106
- end
107
- private_class_method :call_blocks
110
+ end.compact.each { |block| block.call(record) }
111
+ end
108
112
 
109
- def self.convert_to_class(klass)
110
- @class_cache[klass] ||= Object.const_get(camelize(klass))
111
- rescue NameError
112
- raise Traitor::Error.new("Tried to create a #{camelize(klass)}, but it does not exist!")
113
- end
114
- private_class_method :convert_to_class
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
- def self.get_attributes_from_traits(klass, traits)
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
- traits = [:default_traits] + traits # always include default_traits as the first thing
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
- cache_key = klass.to_s + ':' + traits.join(':')
123
- @trait_cache[cache_key] ||= {}.tap do |attributes|
124
- traits.each { |trait| attributes.merge!(library[trait] || {}) }
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
- # use late resolution on lambda values by calling them here as part of constructing a new hash
128
- Hash[
129
- @trait_cache[cache_key].map do |attribute, value|
130
- [attribute, value.is_a?(Proc) && ![:after_build, :after_create].include?(attribute) ? value.call : value]
131
- end
132
- ]
133
- end
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
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-26 00:00:00.000000000 Z
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: rake
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: rspec-its
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: timecop
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: pry
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