kentouzu 0.1.2 → 0.2.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: b39f53d72a27a2ab22bc2d2ac95627e62ca349c5
4
+ data.tar.gz: 075eee3f632a1a30b30b7ba06f4d36e9ba4da7f9
5
+ SHA512:
6
+ metadata.gz: b1c4405b4bf4d4997fd1ec9195ea3ef9bc7df25e30e3ef7f7501cfa92646a5d107a8dda00a12c92bf789c648c6d45a1076d8b0e67dddb7af1b2015cc2ca07336
7
+ data.tar.gz: fce154503e796c800a21b5186fac0deab7d89b2f8a357696d745258314bbe2493b95d57126b641f417b79ff12d5c8db82d125efec580bdb10d4b4c71b0a25664
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 1.9.3-p392
1
+ 2.1.3
data/CHANGELOG.md CHANGED
@@ -1,6 +1,19 @@
1
+ ## v0.2.0
2
+
3
+ * Breaking changes to the way objects are serialized and deserialized.
4
+ * `has_many` associations are now serialized along with the object.
5
+ * Deprecated `drafts_on` and `drafts_off` in favor of `drafts_on!` and `drafts_off!`.
6
+ * Added `Kentouzu.enabled_for_model` and `Kentouzu.enabled_for_model?`.
7
+ * Added `Kentouzu.active_record_protected_attributes?` to enable handling of attr_accessible.
8
+ * Attempt to load `protected_attributes` gem if it's available.
9
+ * Added `Draft.with_source_keys`.
10
+ * Deprecated `Draft#approve` and `Draft#reject`.
11
+ * Added override for `save!`.
12
+
1
13
  ## v0.1.2
2
14
 
3
15
  * Added callbacks for `before_draft_save`, `after_draft_save`, and `around_draft_save`.
16
+ * Fixed a bug where invalid attributes were merged from controller options when saving a draft.
4
17
 
5
18
  ## v0.1.1
6
19
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- kentouzu (0.1.2)
4
+ kentouzu (0.2.0)
5
5
  activerecord (>= 3.0)
6
6
  railties (>= 3.0)
7
7
 
data/kentouzu.gemspec CHANGED
@@ -1,17 +1,14 @@
1
- # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path('../lib', __FILE__)
1
+ $LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
3
2
  require 'kentouzu/version'
4
3
 
5
4
  Gem::Specification.new do |s|
6
5
  s.name = 'kentouzu'
7
6
  s.version = Kentouzu::VERSION
8
- s.authors = ['Sean Eshbaugh']
9
- s.email = ['seaneshbaugh@gmail.com']
10
- s.homepage = 'https://github.com/seaneshbaugh/kentouzu'
11
7
  s.summary = 'Add drafts to ActiveRecord models.'
12
- s.description = 'Add drafts to ActiveRecord models.'
13
-
14
- s.rubyforge_project = 'kentouzu'
8
+ s.description = s.summary
9
+ s.homepage = 'https://github.com/seaneshbaugh/kentouzu'
10
+ s.authors = ['Sean Eshbaugh']
11
+ s.email = 'seaneshbaugh@gmail.com'
15
12
 
16
13
  s.files = `git ls-files`.split("\n")
17
14
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
@@ -9,7 +9,6 @@ module Kentouzu
9
9
  source_root File.expand_path('../templates', __FILE__)
10
10
 
11
11
  desc 'Generates (but does not run) a migration to add a drafts table.'
12
-
13
12
  def create_migration_file
14
13
  migration_template 'create_drafts.rb', 'db/migrate/create_drafts.rb'
15
14
  end
@@ -17,21 +17,21 @@ module Kentouzu
17
17
  end
18
18
 
19
19
  def drafts_enabled_for_controller
20
- true
20
+ Kentouzu.enabled?
21
21
  end
22
22
 
23
23
  private
24
24
 
25
25
  def set_drafts_source
26
- ::Kentouzu.source = user_for_drafts
26
+ Kentouzu.source = user_for_drafts
27
27
  end
28
28
 
29
29
  def set_drafts_controller_info
30
- ::Kentouzu.controller_info = info_for_drafts
30
+ Kentouzu.controller_info = info_for_drafts
31
31
  end
32
32
 
33
33
  def set_drafts_enabled_for_controller
34
- ::Kentouzu.enabled_for_controller = drafts_enabled_for_controller
34
+ Kentouzu.enabled_for_controller = drafts_enabled_for_controller
35
35
  end
36
36
  end
37
37
  end
@@ -1,4 +1,8 @@
1
1
  class Draft < ActiveRecord::Base
2
+ if Kentouzu.active_record_protected_attributes?
3
+ attr_accessible :item_type, :item_id, :event, :source_type, :source_id, :object
4
+ end
5
+
2
6
  belongs_to :item, :polymorphic => true
3
7
 
4
8
  belongs_to :source, :polymorphic => true
@@ -6,7 +10,11 @@ class Draft < ActiveRecord::Base
6
10
  validates_presence_of :event
7
11
 
8
12
  def self.with_item_keys(item_type, item_id)
9
- scoped :conditions => { :item_type => item_type, :item_id => item_id }
13
+ where :item_type => item_type, :item_id => item_id
14
+ end
15
+
16
+ def self.with_source_keys(source_type, source_id)
17
+ where :source_type => source_type, :source_id => source_id
10
18
  end
11
19
 
12
20
  def self.creates
@@ -17,57 +25,97 @@ class Draft < ActiveRecord::Base
17
25
  where :event => 'update'
18
26
  end
19
27
 
20
- scope :subsequent, lambda { |draft| where(["#{self.primary_key} > ?", draft]).order("#{self.primary_key} ASC") }
28
+ def subsequent(obj, timestamp_arg = false)
29
+ if timestamp_arg != true && self.primary_key_is_int?
30
+ where(arel_table[primary_key].gt(obj.id)).order(arel_table[primary_key].asc)
31
+ else
32
+ obj = obj.send(Kentouzu.timestamp_field) if obj.is_a?(self)
21
33
 
22
- scope :preceding, lambda { |draft| where(["#{self.primary_key} < ?}", draft]).order("#{self.primary_key} DESC") }
34
+ where(arel_table[Kentouzu.timestamp_field].gt(obj)).order(self.timestamp_sort_order)
35
+ end
36
+ end
23
37
 
24
- scope :following, lambda { |timestamp| where(["#{Kentouzu.timestamp_field} > ?"], timestamp).order("#{Kentouzu.timestamp_field} ASC, #{self.primary_key} ASC") }
38
+ def preceding(obj, timestamp_arg = false)
39
+ if timestamp_arg != true && self.primary_key_is_int?
40
+ where(arel_table[primary_key].lt(obj.id)).order(arel_table[primary_key].asc)
41
+ else
42
+ obj = obj.send(Kentouzu.timestamp_field) if obj.is_a?(self)
25
43
 
26
- scope :between, lambda { |start_time, end_time| where(["#{Kentouzu.timestamp_field} > ? AND #{Kentouzu.timestamp_field} < ?", start_time, end_time]).order("#{Kentouzu.timestamp_field} ASC, #{self.primary_key} ASC") }
44
+ where(arel_table[Kentouzu.timestamp_field].lt(obj)).order(self.timestamp_sort_order)
45
+ end
46
+ end
47
+
48
+ def following(timestamp)
49
+ where(arel_table[Kentouzu.timestamp_field].gt(timestamp)).order(self.timestamp_sort_order)
50
+ end
51
+
52
+ def between(start_time, end_time)
53
+ where(arel_tabl[Kentouzu.timestamp_field].gt(start_time).and(arel_table[Kentouzu.timestamp_field].lt(end_time))).order(self.timestamp_sort_order)
54
+ end
55
+
56
+ def timestamp_sort_order(direction = 'asc')
57
+ [arel_table[Kentouzu.timestamp_field].send(direction.downcase)].tap do |array|
58
+ array << arel_table[primary_key].send(direction.downcase) if self.primary_key_is_int?
59
+ end
60
+ end
27
61
 
62
+ # Restore the item from this draft.
63
+ #
64
+ # Options:
65
+ # :has_one Set to `false` to disable has_one reification.
66
+ # Set to a float to change the lookback time.
28
67
  def reify(options = {})
68
+ return nil if object.nil?
69
+
29
70
  without_identity_map do
30
71
  options[:has_one] = 3 if options[:has_one] == true
72
+
31
73
  options.reverse_merge! :has_one => false
32
74
 
33
- unless object.nil?
34
- #This appears to be necessary if for some reason the draft's model hasn't been loaded (such as when done in the console).
35
- require self.item_type.underscore
75
+ #This appears to be necessary if for some reason the draft's model hasn't been loaded (such as when done in the console).
76
+ require self.item_type.underscore
36
77
 
37
- loaded_object = YAML::load object
78
+ loaded_object = YAML::load object
38
79
 
39
- if item
40
- model = item
41
- else
42
- inheritance_column_name = item_type.constantize.inheritance_column
80
+ if item
81
+ model = item
82
+ else
83
+ inheritance_column_name = item_type.constantize.inheritance_column
43
84
 
44
- class_name = loaded_object.respond_to?(inheritance_column_name.to_sym) && loaded_object.send(inheritance_column_name.to_sym).present? ? loaded_object.send(inheritance_column_name.to_sym) : item_type
85
+ class_name = loaded_object.respond_to?(inheritance_column_name.to_sym) && loaded_object.send(inheritance_column_name.to_sym).present? ? loaded_object.send(inheritance_column_name.to_sym) : item_type
45
86
 
46
- klass = class_name.constantize
87
+ klass = class_name.constantize
47
88
 
48
- model = klass.new
49
- end
89
+ model = klass.new
90
+ end
50
91
 
51
- loaded_object.attributes.each do |key, value|
52
- if model.respond_to?("#{key}=")
53
- model.send :write_attribute, key.to_sym, value
92
+ has_many_associations = model.class.reflect_on_all_associations(:has_many).reject { |association| association.name == :drafts }.map { |association| association.name }
93
+
94
+ loaded_object.each do |key, value|
95
+ if model.respond_to?("#{key}=")
96
+ if has_many_associations.include?(key.to_sym)
97
+ model.send "#{key}=".to_sym, value.map { |v| model.send(key.to_sym).proxy_association.klass.new(v) }
54
98
  else
55
- logger.warn "Attribute #{key} does not exist on #{item_type} (Draft ID: #{id})."
99
+ model.send :write_attribute, key.to_sym, value
56
100
  end
101
+ else
102
+ logger.warn "Attribute #{key} does not exist on #{item_type} (Draft ID: #{id})."
57
103
  end
104
+ end
58
105
 
59
- model.send "#{model.class.draft_association_name}=", self
60
-
61
- unless options[:has_one] == false
62
- reify_has_ones model, options[:has_one]
63
- end
106
+ model.send "#{model.class.draft_association_name}=", self
64
107
 
65
- model
108
+ unless options[:has_one] == false
109
+ reify_has_ones model, options[:has_one]
66
110
  end
111
+
112
+ model
67
113
  end
68
114
  end
69
115
 
70
116
  def approve
117
+ warn 'DEPRECATED: `approve` should be handled by your application, not Kentouzu. Will be removed in Kentouzu 0.3.0.'
118
+
71
119
  model = self.reify
72
120
 
73
121
  if model
@@ -88,9 +136,17 @@ class Draft < ActiveRecord::Base
88
136
  end
89
137
 
90
138
  def reject
139
+ warn 'DEPRECATED: `reject` should be handled by your application, not Kentouzu. Will be removed in Kentouzu 0.3.0.'
140
+
91
141
  self.destroy
92
142
  end
93
143
 
144
+ def primary_key_is_int?
145
+ @primary_key_is_int ||= columns_hash[primary_key].type == :integer
146
+ rescue
147
+ true
148
+ end
149
+
94
150
  private
95
151
 
96
152
  def without_identity_map(&block)
@@ -5,41 +5,59 @@ module Kentouzu
5
5
  end
6
6
 
7
7
  module ClassMethods
8
+ # By calling this in your model all subsequent calls to save will instead create a draft.
9
+ # Drafts are available through the `drafts` association.
10
+ #
11
+ # Options:
12
+ # :class_name The name of a custom Draft class. Should inherit from `Kentouzu::Draft`.
13
+ # Default is `'Draft'`.
14
+ # :draft The name for the method which returns the draft the instance was reified from.
15
+ # Default is `:draft`.
16
+ # :drafts The name to use for the drafts association.
17
+ # Default is `:drafts`.
18
+ # :if Proc that allows you to specify the conditions under which drafts are made.
19
+ # :ignore An Array of attributes that will be ignored when creating a `Draft`.
20
+ # Can also accept a Has as an argument where each key is the attribute to ignore (either
21
+ # a `String` or `Symbol`) and each value is a `Proc` whose return value, `true` or
22
+ # `false`, determines if it is ignored.
23
+ # :meta A hash of extra data to store. Each key in the hash (either a `String` or `Symbol`)
24
+ # must be a column on the `drafts` table, otherwise it is ignored. You must add these
25
+ # columns yourself. The values are either objects or procs (which are called with `self`,
26
+ # i.e. the model the draft is being made from).
27
+ # :on An array of events that will cause a draft to be created.
28
+ # Defaults to `[:create, :update, :destroy]`.
29
+ # :only Inverse of the `:ignore` option. Only the attributes supplied will be passed along to
30
+ # the draft.
31
+ # :unless Proc that allows you to specify the conditions under which drafts are not made.
8
32
  def has_drafts(options = {})
33
+ # Only include the instance methods when this `has_drafts` is called to avoid cluttering up models.
9
34
  send :include, InstanceMethods
10
35
 
36
+ # Add `before_draft_save`, `after_draft_save`, and `around_draft_save` callbacks.
11
37
  send :define_model_callbacks, :draft_save
12
38
 
13
39
  class_attribute :draft_association_name
14
40
  self.draft_association_name = options[:draft] || :draft
15
41
 
42
+ # The draft this instance was reified from.
16
43
  attr_accessor self.draft_association_name
17
44
 
18
45
  class_attribute :draft_class_name
19
46
  self.draft_class_name = options[:class_name] || 'Draft'
20
47
 
21
- class_attribute :ignore
22
- self.ignore = ([options[:ignore]].flatten.compact || []).map &:to_s
48
+ class_attribute :draft_options
49
+ self.draft_options = options.dup
23
50
 
24
- class_attribute :if_condition
25
- self.if_condition = options[:if]
26
-
27
- class_attribute :unless_condition
28
- self.unless_condition = options[:unless]
29
-
30
- class_attribute :skip
31
- self.skip = ([options[:skip]].flatten.compact || []).map &:to_s
32
-
33
- class_attribute :only
34
- self.only = ([options[:only]].flatten.compact || []).map &:to_s
51
+ [:ignore, :only].each do |option|
52
+ draft_options[option] = [draft_options[option]].flatten.compact.map { |attr| attr.is_a?(Hash) ? attr.stringify_keys : attr.to_s }
53
+ end
35
54
 
36
- class_attribute :drafts_enabled_for_model
37
- self.drafts_enabled_for_model = true
55
+ draft_options[:meta] ||= {}
38
56
 
39
57
  class_attribute :drafts_association_name
40
58
  self.drafts_association_name = options[:drafts] || :drafts
41
59
 
42
- if ActiveRecord::VERSION::STRING.to_f >= 4.0 # `has_many` syntax for specifying order uses a lambda in Rails 4
60
+ if ActiveRecord::VERSION::MAJOR >= 4 # `has_many` syntax for specifying order uses a lambda in Rails 4
43
61
  has_many self.drafts_association_name,
44
62
  lambda { order("#{Kentouzu.timestamp_field} ASC, #{self.primary_key} ASC") },
45
63
  :class_name => draft_class_name,
@@ -49,7 +67,7 @@ module Kentouzu
49
67
  has_many self.drafts_association_name,
50
68
  :class_name => draft_class_name,
51
69
  :as => :item,
52
- :order => "#{Kentouzu.timestamp_field} ASC, #{self.draft_class_name.constantize.primary_key} ASC",
70
+ :order => "#{Kentouzu.timestamp_field} ASC, #{self.draft_class.primary_key} ASC",
53
71
  :dependent => :destroy
54
72
  end
55
73
 
@@ -58,7 +76,7 @@ module Kentouzu
58
76
  end
59
77
 
60
78
  define_singleton_method "all_with_reified_#{drafts_association_name.to_s}".to_sym do |order_by = Kentouzu.timestamp_field, &block|
61
- existing_drafts = Draft.where("`drafts`.`item_type` = \"#{self.base_class.name}\" AND `drafts`.`item_id` IS NOT NULL").group_by { |draft| draft.item_id }.map { |k, v| v.sort_by { |draft| draft.created_at }.last }
79
+ existing_drafts = Draft.where("`drafts`.`item_type` = \"#{self.base_class.name}\" AND `drafts`.`item_id` IS NOT NULL").group_by { |draft| draft.item_id }.map { |_, v| v.sort_by { |draft| draft.created_at }.last }
62
80
 
63
81
  new_drafts = Draft.where("`drafts`.`item_type` = \"#{self.base_class.name}\" AND `drafts`.`item_id` IS NULL")
64
82
 
@@ -83,42 +101,59 @@ module Kentouzu
83
101
  all_objects
84
102
  end
85
103
 
104
+ def drafts_off!
105
+ Kentouzu.enabled_for_model(self, false)
106
+ end
107
+
86
108
  def drafts_off
87
- self.drafts_enabled_for_model = false
109
+ warn 'DEPRECATED: use `drafts_off!` instead of `drafts_off`. Will be removed in Kentouzu 0.3.0.'
110
+
111
+ self.drafts_off!
112
+ end
113
+
114
+ def drafts_on!
115
+ Kentouzu.enabled_for_model(self, true)
88
116
  end
89
117
 
90
118
  def drafts_on
91
- self.drafts_enabled_for_model = true
119
+ warn 'DEPRECATED: use `drafts_on!` instead of `drafts_on`. Will be removed in Kentouzu 0.3.0.'
120
+
121
+ self.drafts_on!
122
+ end
123
+
124
+ def drafts_enabled_for_model?
125
+ Kentouzu.enabled_for_model?(self)
126
+ end
127
+
128
+ def draft_class
129
+ @draft_class ||= draft_class_name.constantize
92
130
  end
93
131
  end
94
132
  end
95
133
 
96
134
  module InstanceMethods
135
+ # Override the default `save` method and replace it with one that checks to see if a draft should be saved.
136
+ # If a draft should be saved the original object instance is left untouched and a new draft is created.
97
137
  def self.included(base)
98
138
  default_save = base.instance_method(:save)
99
139
 
100
140
  base.send :define_method, :save do
101
141
  if switched_on? && save_draft?
102
- data = {
103
- :item_type => self.class.base_class.to_s,
104
- :item_id => self.id,
105
- :event => self.persisted? ? 'update' : 'create',
106
- :source_type => Kentouzu.source.present? ? Kentouzu.source.class.to_s : nil,
107
- :source_id => Kentouzu.source.present? ? Kentouzu.source.id : nil,
108
- :object => self.to_yaml
109
- }
110
-
111
- data.merge!(Kentouzu.controller_info.slice(:item_type, :item_id, :event, :source_type, :source_id) || {})
112
-
113
- draft = Draft.new(data)
114
-
115
- run_callbacks :draft_save do
116
- draft.save
117
- end
142
+ save_draft
118
143
  else
119
144
  default_save.bind(self).call
120
145
  end
121
146
  end
147
+
148
+ default_save_with_bang = base.instance_method(:save!)
149
+
150
+ base.send :define_method, :save! do
151
+ if switched_on? && save_draft?
152
+ save_draft
153
+ else
154
+ default_save_with_bang.bind(self).call
155
+ end
156
+ end
122
157
  end
123
158
 
124
159
  def live?
@@ -151,6 +186,10 @@ module Kentouzu
151
186
  self.class.drafts_on if drafts_were_enabled
152
187
  end
153
188
 
189
+ def drafts_enabled_for_model?
190
+ self.class.drafts_enabled_for_model?
191
+ end
192
+
154
193
  private
155
194
 
156
195
  def draft_class
@@ -161,12 +200,61 @@ module Kentouzu
161
200
  send self.class.draft_association_name
162
201
  end
163
202
 
203
+ def merge_metadata(data)
204
+ draft_options[:meta].each do |key, value|
205
+ if value.respond_to?(:call)
206
+ data[key] = value.call(self)
207
+ elsif value.is_a?(Symbol) && respond_to?(value)
208
+ data[key] = send(value)
209
+ else
210
+ data[key] = value
211
+ end
212
+ end
213
+
214
+ (Kentouzu.controller_info || {}).each do |key, value|
215
+ if value.respond_to?(:call)
216
+ data[key] = value.call(self)
217
+ elsif value.is_a?(Symbol) && respond_to?(value)
218
+ data[key] = send(value)
219
+ end
220
+ end
221
+
222
+ data
223
+ end
224
+
225
+ def save_draft
226
+ data = {
227
+ :item_type => self.class.base_class.to_s,
228
+ :item_id => self.id,
229
+ :event => draft_event.to_s,
230
+ :source_type => Kentouzu.source.present? ? Kentouzu.source.class.to_s : nil,
231
+ :source_id => Kentouzu.source.present? ? Kentouzu.source.id : nil,
232
+ :object => self.as_json(include: self.class.reflect_on_all_associations(:has_many).map { |a| a.name }.reject { |a| a == :drafts }).to_yaml
233
+ }
234
+
235
+ draft = Draft.new(merge_metadata(data))
236
+
237
+ run_callbacks :draft_save do
238
+ draft.save
239
+ end
240
+ end
241
+
242
+ def draft_event
243
+ @draft_event ||= self.persisted? ? :update : :create
244
+ end
245
+
164
246
  def switched_on?
165
- Kentouzu.enabled? && Kentouzu.enabled_for_controller? && self.class.drafts_enabled_for_model
247
+ Kentouzu.enabled? && Kentouzu.enabled_for_controller? && self.drafts_enabled_for_model?
166
248
  end
167
249
 
168
250
  def save_draft?
169
- (if_condition.blank? || if_condition.call(self)) && !unless_condition.try(:call, self)
251
+ on_events = Array(self.draft_options[:on])
252
+
253
+ if_condition = self.draft_options[:if]
254
+
255
+ unless_condition = self.draft_options[:unless]
256
+
257
+ (on_events.empty? || on_events.include?(draft_event)) && (if_condition.blank? || if_condition.call(self)) && !unless_condition.try(:call, self)
170
258
  end
171
259
  end
172
260
  end
@@ -1,3 +1,3 @@
1
1
  module Kentouzu
2
- VERSION = '0.1.2'
2
+ VERSION = '0.2.0'
3
3
  end
data/lib/kentouzu.rb CHANGED
@@ -4,64 +4,110 @@ require 'yaml'
4
4
  require 'kentouzu/config'
5
5
  require 'kentouzu/controller'
6
6
  require 'kentouzu/has_drafts'
7
- require 'kentouzu/draft'
8
7
 
9
8
  module Kentouzu
9
+ # Switches Kentouzu on or off globally.
10
10
  def self.enabled=(value)
11
11
  Kentouzu.config.enabled = value
12
12
  end
13
13
 
14
+ # Returns `true` if Kentouzu is enabled globally, `false` otherwise.
15
+ # Kentouzu is enabled by default.
14
16
  def self.enabled?
15
17
  !!Kentouzu.config.enabled
16
18
  end
17
19
 
20
+ # Switches Kentouzu on or off for the current request.
18
21
  def self.enabled_for_controller=(value)
19
22
  drafts_store[:request_enabled_for_controller] = value
20
23
  end
21
24
 
25
+ # Returns `true` if Kentouzu is enabled for the current request, `false` otherwise.
22
26
  def self.enabled_for_controller?
23
27
  !!drafts_store[:request_enabled_for_controller]
24
28
  end
25
29
 
30
+ # Switches Kentouzu on or off for the model for the current request.
31
+ def self.enabled_for_model(model, value)
32
+ drafts_store[:"enabled_for_#{model}"] = value
33
+ end
34
+
35
+ # Returns `true` if Kentouzu is enabled for the model for the current request, `false` otherwise.
36
+ def self.enabled_for_model?(model)
37
+ !!drafts_store.fetch(:"enabled_for_#{model}", true)
38
+ end
39
+
40
+ # Set the field which records when a draft was created.
26
41
  def self.timestamp_field=(field_name)
27
42
  Kentouzu.config.timestamp_field = field_name
28
43
  end
29
44
 
45
+ # Returns the field which records when a draft was created.
30
46
  def self.timestamp_field
31
47
  Kentouzu.config.timestamp_field
32
48
  end
33
49
 
50
+ # Sets who is responsible for creating the draft.
51
+ # Inside of a controller this will automatically be set to `current_user`.
52
+ # Outside of a controller it will need to be set manually.
34
53
  def self.source=(value)
35
54
  drafts_store[:source] = value
36
55
  end
37
56
 
57
+ # Returns who is responsible for creating the draft.
38
58
  def self.source
39
59
  drafts_store[:source]
40
60
  end
41
61
 
62
+ # Sets any information from the controller that you want Kentouzu to store.
42
63
  def self.controller_info=(value)
43
64
  drafts_store[:controller_info] = value
44
65
  end
45
66
 
67
+ # Returns any information from the controller that you want Kentouzu to store.
46
68
  def self.controller_info
47
69
  drafts_store[:controller_info]
48
70
  end
49
71
 
72
+ # Returns `true` if ActiveRecord requires mass assigned attributes to be whitelisted via `attr_accessible`, `false` otherwise.
73
+ def self.active_record_protected_attributes?
74
+ @active_record_protected_attributes ||= ActiveRecord::VERSION::MAJOR < 4 || !!defined?(ProtectedAttributes)
75
+ end
76
+
50
77
  private
51
78
 
79
+ # Thread-safe hash to hold Kentouzu's data.
80
+ # Initialized to enable Kentouzu for all controllers.
52
81
  def self.drafts_store
53
82
  Thread.current[:draft] ||= { :request_enabled_for_controller => true }
54
83
  end
55
84
 
85
+ # Returns Kentouzu's configuration object.
56
86
  def self.config
57
87
  @@config ||= Kentouzu::Config.instance
58
88
  end
59
89
  end
60
90
 
91
+ require 'kentouzu/draft'
92
+
93
+ # Ensure `protected_attributes` gem gets required if it is available before the `Draft` class is loaded.
94
+ unless Kentouzu.active_record_protected_attributes?
95
+ Kentouzu.send(:remove_instance_variable, :@active_record_protected_attributes)
96
+
97
+ begin
98
+ require 'protected_attributes'
99
+ rescue LoadError
100
+ # Don't blow up if the `protected_attributes` gem is not available.
101
+ nil
102
+ end
103
+ end
104
+
105
+ # Include `Kentouzu::Model` into `ActiveRecord::Base`
61
106
  ActiveSupport.on_load(:active_record) do
62
107
  include Kentouzu::Model
63
108
  end
64
109
 
110
+ # Include `Kentouzu::Controller` into `ActionController::Base`
65
111
  ActiveSupport.on_load(:action_controller) do
66
112
  include Kentouzu::Controller
67
113
  end
metadata CHANGED
@@ -1,187 +1,165 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kentouzu
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
5
- prerelease:
4
+ version: 0.2.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Sean Eshbaugh
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2014-10-17 00:00:00.000000000 Z
11
+ date: 2014-10-21 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: railties
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - ">="
20
18
  - !ruby/object:Gem::Version
21
19
  version: '3.0'
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - ">="
28
25
  - !ruby/object:Gem::Version
29
26
  version: '3.0'
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: activerecord
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - ">="
36
32
  - !ruby/object:Gem::Version
37
33
  version: '3.0'
38
34
  type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - ">="
44
39
  - !ruby/object:Gem::Version
45
40
  version: '3.0'
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: capybara
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
- - - ! '>='
45
+ - - ">="
52
46
  - !ruby/object:Gem::Version
53
47
  version: '0'
54
48
  type: :development
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
- - - ! '>='
52
+ - - ">="
60
53
  - !ruby/object:Gem::Version
61
54
  version: '0'
62
55
  - !ruby/object:Gem::Dependency
63
56
  name: database_cleaner
64
57
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
58
  requirements:
67
- - - ! '>='
59
+ - - ">="
68
60
  - !ruby/object:Gem::Version
69
61
  version: '0'
70
62
  type: :development
71
63
  prerelease: false
72
64
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
65
  requirements:
75
- - - ! '>='
66
+ - - ">="
76
67
  - !ruby/object:Gem::Version
77
68
  version: '0'
78
69
  - !ruby/object:Gem::Dependency
79
70
  name: jquery-rails
80
71
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
72
  requirements:
83
- - - ! '>='
73
+ - - ">="
84
74
  - !ruby/object:Gem::Version
85
75
  version: '0'
86
76
  type: :development
87
77
  prerelease: false
88
78
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
79
  requirements:
91
- - - ! '>='
80
+ - - ">="
92
81
  - !ruby/object:Gem::Version
93
82
  version: '0'
94
83
  - !ruby/object:Gem::Dependency
95
84
  name: rake
96
85
  requirement: !ruby/object:Gem::Requirement
97
- none: false
98
86
  requirements:
99
- - - ! '>='
87
+ - - ">="
100
88
  - !ruby/object:Gem::Version
101
89
  version: '0'
102
90
  type: :development
103
91
  prerelease: false
104
92
  version_requirements: !ruby/object:Gem::Requirement
105
- none: false
106
93
  requirements:
107
- - - ! '>='
94
+ - - ">="
108
95
  - !ruby/object:Gem::Version
109
96
  version: '0'
110
97
  - !ruby/object:Gem::Dependency
111
98
  name: rails
112
99
  requirement: !ruby/object:Gem::Requirement
113
- none: false
114
100
  requirements:
115
- - - ! '>='
101
+ - - ">="
116
102
  - !ruby/object:Gem::Version
117
103
  version: '3.2'
118
104
  type: :development
119
105
  prerelease: false
120
106
  version_requirements: !ruby/object:Gem::Requirement
121
- none: false
122
107
  requirements:
123
- - - ! '>='
108
+ - - ">="
124
109
  - !ruby/object:Gem::Version
125
110
  version: '3.2'
126
111
  - !ruby/object:Gem::Dependency
127
112
  name: rspec-rails
128
113
  requirement: !ruby/object:Gem::Requirement
129
- none: false
130
114
  requirements:
131
- - - ! '>='
115
+ - - ">="
132
116
  - !ruby/object:Gem::Version
133
117
  version: '0'
134
118
  type: :development
135
119
  prerelease: false
136
120
  version_requirements: !ruby/object:Gem::Requirement
137
- none: false
138
121
  requirements:
139
- - - ! '>='
122
+ - - ">="
140
123
  - !ruby/object:Gem::Version
141
124
  version: '0'
142
125
  - !ruby/object:Gem::Dependency
143
126
  name: shoulda-matchers
144
127
  requirement: !ruby/object:Gem::Requirement
145
- none: false
146
128
  requirements:
147
- - - ! '>='
129
+ - - ">="
148
130
  - !ruby/object:Gem::Version
149
131
  version: '0'
150
132
  type: :development
151
133
  prerelease: false
152
134
  version_requirements: !ruby/object:Gem::Requirement
153
- none: false
154
135
  requirements:
155
- - - ! '>='
136
+ - - ">="
156
137
  - !ruby/object:Gem::Version
157
138
  version: '0'
158
139
  - !ruby/object:Gem::Dependency
159
140
  name: sqlite3
160
141
  requirement: !ruby/object:Gem::Requirement
161
- none: false
162
142
  requirements:
163
- - - ! '>='
143
+ - - ">="
164
144
  - !ruby/object:Gem::Version
165
145
  version: '0'
166
146
  type: :development
167
147
  prerelease: false
168
148
  version_requirements: !ruby/object:Gem::Requirement
169
- none: false
170
149
  requirements:
171
- - - ! '>='
150
+ - - ">="
172
151
  - !ruby/object:Gem::Version
173
152
  version: '0'
174
153
  description: Add drafts to ActiveRecord models.
175
- email:
176
- - seaneshbaugh@gmail.com
154
+ email: seaneshbaugh@gmail.com
177
155
  executables: []
178
156
  extensions: []
179
157
  extra_rdoc_files: []
180
158
  files:
181
- - .gitignore
182
- - .rspec
183
- - .ruby-gemset
184
- - .ruby-version
159
+ - ".gitignore"
160
+ - ".rspec"
161
+ - ".ruby-gemset"
162
+ - ".ruby-version"
185
163
  - CHANGELOG.md
186
164
  - Gemfile
187
165
  - Gemfile.lock
@@ -247,33 +225,26 @@ files:
247
225
  - spec/spec_helper.rb
248
226
  homepage: https://github.com/seaneshbaugh/kentouzu
249
227
  licenses: []
228
+ metadata: {}
250
229
  post_install_message:
251
230
  rdoc_options: []
252
231
  require_paths:
253
232
  - lib
254
233
  required_ruby_version: !ruby/object:Gem::Requirement
255
- none: false
256
234
  requirements:
257
- - - ! '>='
235
+ - - ">="
258
236
  - !ruby/object:Gem::Version
259
237
  version: '0'
260
- segments:
261
- - 0
262
- hash: -3194602278824882459
263
238
  required_rubygems_version: !ruby/object:Gem::Requirement
264
- none: false
265
239
  requirements:
266
- - - ! '>='
240
+ - - ">="
267
241
  - !ruby/object:Gem::Version
268
242
  version: '0'
269
- segments:
270
- - 0
271
- hash: -3194602278824882459
272
243
  requirements: []
273
- rubyforge_project: kentouzu
274
- rubygems_version: 1.8.25
244
+ rubyforge_project:
245
+ rubygems_version: 2.2.2
275
246
  signing_key:
276
- specification_version: 3
247
+ specification_version: 4
277
248
  summary: Add drafts to ActiveRecord models.
278
249
  test_files:
279
250
  - spec/dummy/Rakefile