reference_tracking 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,13 @@
1
+ require 'active_support/core_ext/kernel/singleton_class'
2
+ require 'action_controller'
3
+
4
+ module ReferenceTracking
5
+ TAGS_HEADER = 'rack-cache.tags'
6
+
7
+ autoload :ActionController, 'reference_tracking/action_controller'
8
+ autoload :IvarProxy, 'reference_tracking/ivar_proxy'
9
+ autoload :Tracker, 'reference_tracking/tracker'
10
+ autoload :References, 'reference_tracking/references'
11
+ end
12
+
13
+ ActionController::Base.send(:extend, ReferenceTracking::ActionController::ActMacro)
@@ -0,0 +1,40 @@
1
+ module ReferenceTracking
2
+ module ActionController
3
+ module ActMacro
4
+ def tracks(*args)
5
+ unless tracks_references?
6
+ include ReferenceTracking::ActionController
7
+
8
+ class_inheritable_accessor :reference_tracking_options
9
+ self.reference_tracking_options = { :header => TAGS_HEADER }
10
+ end
11
+
12
+ options = args.extract_options!
13
+ actions = Array(options.delete(:only) || [:index, :show]) - Array(options.delete(:except))
14
+ args << options unless options.empty?
15
+
16
+ actions.map(&:to_sym).each do |action|
17
+ self.reference_tracking_options[action] ||= []
18
+ self.reference_tracking_options[action] += args
19
+ end
20
+ end
21
+
22
+ def tracks_references?
23
+ respond_to?(:reference_tracking_options) && reference_tracking_options.present?
24
+ end
25
+ end
26
+
27
+ # TODO could this hook into instrumentation?
28
+ # ActiveSupport::Notifications.instrument("render_template.action_view", ...)?
29
+
30
+ def render(*)
31
+ methods = reference_tracking_options[params[:action].to_sym] || {}
32
+ @_references = ReferenceTracking::References.new(self, methods)
33
+
34
+ result = super
35
+
36
+ headers[reference_tracking_options[:header]] = @_references.tags
37
+ result
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,26 @@
1
+ module ReferenceTracking
2
+ class IvarProxy
3
+ instance_methods.each { |m| undef_method(m) unless %w(__send__ __id__ inspect).include?(m) }
4
+
5
+ def initialize(owner, name, object, references)
6
+ @owner = owner
7
+ @name = name
8
+ @object = object
9
+ @references = references
10
+ end
11
+
12
+ def respond_to?(method)
13
+ @object.respond_to?(method)
14
+ end
15
+
16
+ def method_missing(method, *args, &block)
17
+ respond_to?(method) ? __track__(method, *args, &block) : super
18
+ end
19
+
20
+ def __track__(method, *args, &block)
21
+ @references << [@object, nil]
22
+ @owner.instance_variable_set(@name, @object)
23
+ @object.send(method, *args, &block)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,13 @@
1
+ module ReferenceTracking
2
+ class References < Array
3
+ def initialize(object, methods)
4
+ Tracker.setup(object, self, methods)
5
+ end
6
+
7
+ def tags
8
+ map do |object, method|
9
+ "#{object.class.name.underscore}-#{object.id}#{":#{method}" if method}"
10
+ end.uniq
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,56 @@
1
+ # tracks :post # => tags post-1.*
2
+ # tracks 'post.title' # => tags post-1.title
3
+ # tracks :post => :blog # => tags blog-1.*
4
+ # tracks :blog => :posts # => tags post-1.*, post-1.*, ...
5
+
6
+ require 'active_support/core_ext/array/wrap'
7
+
8
+ module ReferenceTracking
9
+ module Tracker
10
+ class << self
11
+ def setup(object, references, targets, options = {})
12
+ Array.wrap(targets).each do |target|
13
+ if target.is_a?(Hash)
14
+ target.each { |target, nested| delegate_tracking(object, references, target, nested) }
15
+ elsif options[:delegated]
16
+ send(options[:delegated], object, references, target)
17
+ elsif target.to_s.include?('.')
18
+ delegate_tracking(object, references, *target.to_s.split('.') << :track_calls_to)
19
+ else
20
+ track_calls_on(object, references, target)
21
+ end
22
+ end
23
+ end
24
+
25
+ def tracker_for(object)
26
+ Module.new.tap { |tracker| object.singleton_class.send(:include, tracker) }
27
+ end
28
+
29
+ def track_calls_on(object, references, target)
30
+ tracker_for(object).send(:define_method, target) do |*args|
31
+ super.tap { |object| Array(object).each { |object| references << [object, nil] } }
32
+ end
33
+ end
34
+
35
+ def track_calls_to(object, references, method)
36
+ method = method.to_s.split('.').last if method.to_s.include?('.')
37
+ tracker_for(object).send(:define_method, method) do |*args|
38
+ references << [self, method]
39
+ super
40
+ end
41
+ end
42
+
43
+ def delegate_tracking(object, references, target, delegateds, method = :track_calls_on)
44
+ tracker_for(object).send(:define_method, target) do |*|
45
+ super.tap do |object|
46
+ Array.wrap(delegateds).each do |delegated|
47
+ delegated = [delegated] if delegated.is_a?(Hash)
48
+ _method = delegated.to_s.start_with?('.') ? :track_calls_to : method
49
+ Tracker.setup(object, references, delegated, :delegated => _method)
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,3 @@
1
+ module ReferenceTracking
2
+ VERSION = "0.0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: reference_tracking
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Sven Fuchs
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-09-04 00:00:00 +02:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: "[description]"
23
+ email: svenfuchs@artweb-design.de
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files: []
29
+
30
+ files:
31
+ - lib/reference_tracking.rb
32
+ - lib/reference_tracking/action_controller.rb
33
+ - lib/reference_tracking/ivar_proxy.rb
34
+ - lib/reference_tracking/references.rb
35
+ - lib/reference_tracking/tracker.rb
36
+ - lib/reference_tracking/version.rb
37
+ has_rdoc: true
38
+ homepage: http://github.com/svenfuchs/reference_tracking
39
+ licenses: []
40
+
41
+ post_install_message:
42
+ rdoc_options: []
43
+
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ none: false
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ hash: 3
52
+ segments:
53
+ - 0
54
+ version: "0"
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ hash: 23
61
+ segments:
62
+ - 1
63
+ - 3
64
+ - 6
65
+ version: 1.3.6
66
+ requirements: []
67
+
68
+ rubyforge_project: "[none]"
69
+ rubygems_version: 1.3.7
70
+ signing_key:
71
+ specification_version: 3
72
+ summary: "[summary]"
73
+ test_files: []
74
+