fragmentary 0.1.0 → 0.3
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 +5 -5
- data/CHANGELOG.md +26 -0
- data/README.md +314 -69
- data/fragmentary.gemspec +3 -1
- data/lib/fragmentary/config.rb +65 -0
- data/lib/fragmentary/fragment.rb +120 -67
- data/lib/fragmentary/fragments_helper.rb +41 -26
- data/lib/fragmentary/publisher.rb +3 -1
- data/lib/fragmentary/request.rb +1 -16
- data/lib/fragmentary/request_queue.rb +51 -42
- data/lib/fragmentary/session_user.rb +38 -0
- data/lib/fragmentary/subscriber.rb +3 -1
- data/lib/fragmentary/subscription.rb +5 -2
- data/lib/fragmentary/user_session.rb +123 -21
- data/lib/fragmentary/version.rb +1 -1
- data/lib/fragmentary/widget.rb +6 -3
- data/lib/fragmentary/widget_parser.rb +2 -2
- data/lib/fragmentary.rb +11 -0
- metadata +38 -14
data/fragmentary.gemspec
CHANGED
@@ -22,9 +22,11 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.bindir = "exe"
|
23
23
|
spec.require_paths = ["lib"]
|
24
24
|
|
25
|
-
spec.add_runtime_dependency "rails", "
|
25
|
+
spec.add_runtime_dependency "rails", "~> 5.0"
|
26
26
|
spec.add_runtime_dependency "delayed_job_active_record", "~> 4.1"
|
27
27
|
spec.add_runtime_dependency "wisper-activerecord", "~> 1.0"
|
28
|
+
spec.add_runtime_dependency "http", "~> 3.0.0"
|
29
|
+
spec.add_runtime_dependency "nokogiri"
|
28
30
|
spec.add_development_dependency "bundler", "~> 1.17"
|
29
31
|
spec.add_development_dependency "rake", "~> 10.0"
|
30
32
|
spec.add_development_dependency "rspec", "~> 3.0"
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Fragmentary
|
2
|
+
|
3
|
+
class Config
|
4
|
+
include Singleton
|
5
|
+
attr_accessor :current_user_method, :get_sign_in_path, :post_sign_in_path, :sign_out_path,
|
6
|
+
:users, :default_user_type_mapping, :session_users, :application_root_url_column, :remote_urls
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
# default
|
10
|
+
@current_user_method = :current_user
|
11
|
+
@application_root_url_column = :application_root_url
|
12
|
+
@remote_urls = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def session_users=(session_users)
|
16
|
+
raise "config.session_users must be a Hash" unless session_users.is_a?(Hash)
|
17
|
+
Fragmentary.parse_session_users(session_users)
|
18
|
+
@session_users = session_users
|
19
|
+
end
|
20
|
+
|
21
|
+
def application_root_url_column=(column_name)
|
22
|
+
@application_root_url_column = column_name.to_sym
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.current_user_method
|
27
|
+
self.config.current_user_method
|
28
|
+
end
|
29
|
+
|
30
|
+
# Parse a set of session_user options, creating session_users where needed, and return a set of user_type keys.
|
31
|
+
# session_users may take several forms:
|
32
|
+
# (1) a hash whose keys are user_type strings and whose values have the form {:credentials => credentials},
|
33
|
+
# where 'credentials' is either a hash of parameters to be submitted when logging in or a proc that
|
34
|
+
# returns those parameters.
|
35
|
+
# (2) an array of hashes as described in (1) above.
|
36
|
+
# (3) an array of user_type strings corresponding to SessionUser objects already defined.
|
37
|
+
# (4) an array containing a mixture of user_type strings and hashes as described in (1) above.
|
38
|
+
# Non-hash elements that don't represent existing SessionUser objects should raise an exception. Array
|
39
|
+
# elements that are hashes should be parsed to create new SessionUser objects. Raise an exception on
|
40
|
+
# any attempt to redefine an existing user_type.
|
41
|
+
def self.parse_session_users(session_users = nil)
|
42
|
+
return nil unless session_users
|
43
|
+
if session_users.is_a?(Array)
|
44
|
+
# Fun fact: can't use 'each_with_object' here because 'acc += parse_session_users(v)' would assign
|
45
|
+
# a different object to 'acc' on each iteration, while 'each_with_object' passes the *same* object
|
46
|
+
# to the block on each iteration.
|
47
|
+
session_users.inject([]) do |acc, v|
|
48
|
+
if v.is_a?(Hash)
|
49
|
+
acc + parse_session_users(v)
|
50
|
+
else
|
51
|
+
# v is a user_type, e.g. :admin
|
52
|
+
raise "No SessionUser exists for user_type '#{v}'" unless SessionUser.fetch(v)
|
53
|
+
acc << v
|
54
|
+
end
|
55
|
+
end
|
56
|
+
elsif session_users.is_a?(Hash)
|
57
|
+
session_users.each_with_object([]) do |(k,v), acc|
|
58
|
+
# k is the user_type, v is an options hash that typically looks like {:credentials => login_credentials} where
|
59
|
+
# login_credentials is either a hash of parameters to be submitted at login or a proc that returns those parameters.
|
60
|
+
# In the latter case, the proc is executed when we actually log in to create a new session for the specified user.
|
61
|
+
acc << k if user = SessionUser.new(k,v)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/lib/fragmentary/fragment.rb
CHANGED
@@ -24,13 +24,12 @@ module Fragmentary
|
|
24
24
|
# redundant duplicate request.
|
25
25
|
after_commit :touch_parent, :on => [:update, :destroy]
|
26
26
|
|
27
|
-
attr_accessible :parent_id, :root_id, :record_id, :user_id, :user_type, :key
|
28
|
-
|
29
27
|
attr_accessor :indexed_children
|
30
28
|
|
31
|
-
|
32
|
-
|
33
|
-
|
29
|
+
# Set cache timestamp format to :usec instead of :nsec because the latter is greater precision than Postgres supports,
|
30
|
+
# resulting in mismatches between timestamps on a newly created fragment and one retrieved from the database.
|
31
|
+
# Probably not needed for Rails 5, which uses :usec by default.
|
32
|
+
self.cache_timestamp_format = :usec
|
34
33
|
|
35
34
|
end
|
36
35
|
|
@@ -49,14 +48,14 @@ module Fragmentary
|
|
49
48
|
module ClassMethods
|
50
49
|
|
51
50
|
def root(options)
|
52
|
-
if options[:
|
51
|
+
if fragment = options[:fragment]
|
52
|
+
raise ArgumentError, "You passed Fragment #{fragment.id} to Fragment.root, but it's a child of Fragment #{fragment.parent_id}" if fragment.parent_id
|
53
|
+
else
|
53
54
|
klass, search_attributes, options = base_class.attributes(options)
|
54
55
|
fragment = klass.where(search_attributes).includes(:children).first_or_initialize(options); fragment.save if fragment.new_record?
|
55
56
|
fragment.set_indexed_children if fragment.child_search_key
|
56
|
-
fragment
|
57
|
-
else
|
58
|
-
raise RangeError, "#{options[:type]} is not a root fragment class"
|
59
57
|
end
|
58
|
+
fragment
|
60
59
|
end
|
61
60
|
|
62
61
|
# Each fragment record is unique by type and parent_id (which is nil for a root_fragment) and for some types also by
|
@@ -72,8 +71,14 @@ module Fragmentary
|
|
72
71
|
# Collect the attributes to be used when searching for an existing fragment. Fragments are unique by these values.
|
73
72
|
search_attributes = {}
|
74
73
|
|
75
|
-
parent_id = options.delete(:parent_id)
|
76
|
-
|
74
|
+
if (parent_id = options.delete(:parent_id))
|
75
|
+
search_attributes.merge!(:parent_id => parent_id)
|
76
|
+
else
|
77
|
+
application_root_url_column = Fragmentary.config.application_root_url_column
|
78
|
+
if (application_root_url = options.delete(application_root_url_column)) && column_names.include?(application_root_url_column.to_s)
|
79
|
+
search_attributes.merge!(application_root_url_column => application_root_url)
|
80
|
+
end
|
81
|
+
end
|
77
82
|
|
78
83
|
[:record_id, :user_id, :user_type, :key].each do |attribute_name|
|
79
84
|
if klass.needs?(attribute_name)
|
@@ -94,16 +99,21 @@ module Fragmentary
|
|
94
99
|
@@cache_store ||= Rails.application.config.action_controller.cache_store
|
95
100
|
end
|
96
101
|
|
102
|
+
# ToDo: combine this with Fragment.root
|
97
103
|
def existing(options)
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
104
|
+
if fragment = options[:fragment]
|
105
|
+
raise ArgumentError, "You passed Fragment #{fragment.id} to Fragment.existing, but it's a child of Fragment #{fragment.parent_id}" if fragment.parent_id
|
106
|
+
else
|
107
|
+
options.merge!(:type => name) unless self == base_class
|
108
|
+
raise ArgumentError, "A 'type' attribute is needed in order to retrieve a fragment" unless options[:type]
|
109
|
+
klass, search_attributes, options = base_class.attributes(options)
|
110
|
+
# We merge options because it may include :record_id, which may be needed for uniqueness even
|
111
|
+
# for classes that don't 'need_record_id' if the parent_id isn't available.
|
112
|
+
fragment = klass.where(search_attributes.merge(options)).includes(:children).first
|
113
|
+
# Unlike Fragment.root and Fragment#child we don't instantiate a record if none is found,
|
114
|
+
# so fragment may be nil.
|
115
|
+
fragment.try :set_indexed_children if fragment.try :child_search_key
|
116
|
+
end
|
107
117
|
fragment
|
108
118
|
end
|
109
119
|
|
@@ -111,20 +121,53 @@ module Fragmentary
|
|
111
121
|
self
|
112
122
|
end
|
113
123
|
|
124
|
+
# There is one queue per user_type per application instance (the current app and any external instances). The queues
|
125
|
+
# for all fragments are held in common by the Fragment base class here in @@request_queues but are also indexed on a
|
126
|
+
# subclass basis by an individual subclass's user_types (see the inherited hook below). As well as being accessible
|
127
|
+
# here as Fragment.request_queues, the queues are also available without indexation as RequestQueue.all.
|
114
128
|
def request_queues
|
115
|
-
@@request_queues ||= Hash.new do |
|
116
|
-
hash
|
129
|
+
@@request_queues ||= Hash.new do |hsh, host_url|
|
130
|
+
# As well as acting as a hash key to index the set of request queues for a given target application instance
|
131
|
+
# (for which its uniqueness is the only requirement), host_url is also passed to the RequestQueue constructor,
|
132
|
+
# from which it is used:
|
133
|
+
# (i) by the RequestQueue::Sender to derive the name of the delayed_job queue that will be used to process the
|
134
|
+
# queued requests if the sender is invoked in asynchronous mode - see RequestQueue::Sender#schedulerequests.
|
135
|
+
# (ii) by the Fragmentary::InternalUserSession instantiated by the Sender to configure the session_host.
|
136
|
+
hsh[host_url] = Hash.new do |hsh2, user_type|
|
137
|
+
hsh2[user_type] = RequestQueue.new(user_type, host_url)
|
138
|
+
end
|
117
139
|
end
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
140
|
+
end
|
141
|
+
|
142
|
+
# Subclass-specific request_queues
|
143
|
+
def inherited(subclass)
|
144
|
+
subclass.instance_eval do
|
145
|
+
|
146
|
+
def request_queues
|
147
|
+
super # ensure that @@request_queues has been defined
|
148
|
+
@request_queues ||= begin
|
149
|
+
app_root_url = Rails.application.routes.url_helpers.root_url
|
150
|
+
remote_urls = Fragmentary.config.remote_urls
|
151
|
+
user_types.each_with_object( Hash.new {|hsh0, url| hsh0[url] = {}} ) do |user_type, hsh|
|
152
|
+
# Internal request queues
|
153
|
+
hsh[app_root_url][user_type] = @@request_queues[app_root_url][user_type]
|
154
|
+
# External request queues
|
155
|
+
if remote_urls.any?
|
156
|
+
unless Rails.application.routes.default_url_options[:host]
|
157
|
+
raise "Can't create external request queues without setting Rails.application.routes.default_url_options[:host]"
|
158
|
+
end
|
159
|
+
remote_urls.each {|remote_url| hsh[remote_url][user_type] = @@request_queues[remote_url][user_type]}
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
123
165
|
end
|
166
|
+
super
|
124
167
|
end
|
125
168
|
|
126
|
-
def remove_queued_request(user:,
|
127
|
-
request_queues[user_type(user)].remove_path(request_path
|
169
|
+
def remove_queued_request(user:, request_path:)
|
170
|
+
request_queues.each{|key, hsh| hsh[user_type(user)].remove_path(request_path)}
|
128
171
|
end
|
129
172
|
|
130
173
|
def subscriber
|
@@ -141,7 +184,7 @@ module Fragmentary
|
|
141
184
|
# create or retrieve a Fragment of that class. A user_id is needed for example when caching user-specific content
|
142
185
|
# such as a user profile. When the fragment is instantiated using FragmentsHelper methods 'cache_fragment' or
|
143
186
|
# 'CacheBuilder.cache_child', a :user option is added to the options hash automatically from the value of 'current_user'.
|
144
|
-
# The user_id is extracted from this option in Fragment.
|
187
|
+
# The user_id is extracted from this option in Fragment.attributes.
|
145
188
|
def needs_user_id
|
146
189
|
self.extend NeedsUserId
|
147
190
|
end
|
@@ -151,9 +194,24 @@ module Fragmentary
|
|
151
194
|
# differently depending on the type of user, e.g. to distinguish between content seen by signed in users and those not
|
152
195
|
# signed in. When the fragment is instantiated using FragmentsHelper methods 'cache_fragment' or 'CacheBuilder.cache_child',
|
153
196
|
# a :user option is added to the options hash automatically from the value of 'current_user'. The user_type is extracted
|
154
|
-
# from this option in Fragment.
|
155
|
-
|
197
|
+
# from this option in Fragment.attributes.
|
198
|
+
#
|
199
|
+
# For each class that declares 'needs_user_type', a set of user_types is defined that determines the set of request_queues
|
200
|
+
# that will be used to send requests to the application when a fragment is touched. By default these user_types are defined
|
201
|
+
# globally using 'Fragmentary.setup' but they can alternatively be set on a class-specific basis by passing a :session_users
|
202
|
+
# option to 'needs_user_type'. See 'Fragmentary.parse_session_users' for details.
|
203
|
+
def needs_user_type(options = {})
|
156
204
|
self.extend NeedsUserType
|
205
|
+
instance_eval do
|
206
|
+
@user_type_mapping = options[:user_type_mapping]
|
207
|
+
def self.user_type(user)
|
208
|
+
(@user_type_mapping || Fragmentary.config.default_user_type_mapping).try(:call, user)
|
209
|
+
end
|
210
|
+
@user_types = Fragmentary.parse_session_users(options[:session_users] || options[:types] || options[:user_types])
|
211
|
+
def self.user_types
|
212
|
+
@user_types || Fragmentary.config.session_users.keys
|
213
|
+
end
|
214
|
+
end
|
157
215
|
end
|
158
216
|
|
159
217
|
def needs_key(options = {})
|
@@ -202,17 +260,25 @@ module Fragmentary
|
|
202
260
|
# by the fragment.
|
203
261
|
class << record_type_subscription
|
204
262
|
set_callback :after_destroy, :after, ->{subscriber.client.remove_fragments_for_record(record.id)}
|
263
|
+
set_callback :after_create, :after, ->{subscriber.client.try_request_for_record(record.id)}
|
205
264
|
end
|
206
265
|
end
|
207
266
|
|
208
|
-
|
209
|
-
|
210
|
-
end
|
267
|
+
self.extend RecordClassMethods
|
268
|
+
define_method(:record){record_type.constantize.find(record_id)}
|
211
269
|
end
|
212
270
|
end
|
213
271
|
|
214
|
-
|
215
|
-
|
272
|
+
module RecordClassMethods
|
273
|
+
def remove_fragments_for_record(record_id)
|
274
|
+
where(:record_id => record_id).each(&:destroy)
|
275
|
+
end
|
276
|
+
|
277
|
+
def try_request_for_record(record_id)
|
278
|
+
if requestable?
|
279
|
+
queue_request(request(record_id))
|
280
|
+
end
|
281
|
+
end
|
216
282
|
end
|
217
283
|
|
218
284
|
def needs_record_id?
|
@@ -245,7 +311,7 @@ module Fragmentary
|
|
245
311
|
# hasn't yet been requested, e.g. an assumption created on an article page won't necessarily have been rendered on the
|
246
312
|
# opinion analysis page.
|
247
313
|
def touch_fragments_for_record(record_id)
|
248
|
-
fragments_for_record(record_id).each(&:touch)
|
314
|
+
fragments_for_record(record_id).includes({:parent => :parent}).each(&:touch)
|
249
315
|
end
|
250
316
|
|
251
317
|
def fragments_for_record(record_id)
|
@@ -260,24 +326,12 @@ module Fragmentary
|
|
260
326
|
nil
|
261
327
|
end
|
262
328
|
|
263
|
-
def queue_request(
|
264
|
-
|
265
|
-
if r = request(*args)
|
266
|
-
request_queues.each{|key, queue| queue << r}
|
267
|
-
end
|
329
|
+
def queue_request(request=nil)
|
330
|
+
request_queues.each{|key, hsh| hsh.each{|key2, queue| queue << request}} if request
|
268
331
|
end
|
269
332
|
|
270
333
|
def requestable?
|
271
|
-
respond_to?
|
272
|
-
end
|
273
|
-
|
274
|
-
# Subclasses that define a class method self.request_path also need to override this method
|
275
|
-
def request(*args)
|
276
|
-
if respond_to? :request_path
|
277
|
-
raise "You can't call Fragment.request for a subclass that defines 'request_path'. #{name} needs its own request implementation."
|
278
|
-
else
|
279
|
-
raise "There is no 'request' class method defined for the #{name} class."
|
280
|
-
end
|
334
|
+
respond_to?(:request_path)
|
281
335
|
end
|
282
336
|
|
283
337
|
# The instance method 'request_method' is defined in terms of this.
|
@@ -291,7 +345,11 @@ module Fragmentary
|
|
291
345
|
|
292
346
|
# The instance method 'request_options' is defined in terms of this.
|
293
347
|
def request_options
|
294
|
-
|
348
|
+
{}
|
349
|
+
end
|
350
|
+
|
351
|
+
def request
|
352
|
+
raise NotImplementedError
|
295
353
|
end
|
296
354
|
|
297
355
|
# This method defines the handler for the creation of new list items. The method takes:
|
@@ -382,7 +440,10 @@ module Fragmentary
|
|
382
440
|
# rendered on its own, e.g. inserted by ajax into a parent that is already on the page. In this case the
|
383
441
|
# children won't have already been loaded or indexed.
|
384
442
|
def child(options)
|
385
|
-
|
443
|
+
if child = options[:child]
|
444
|
+
raise ArgumentError, "You passed a child fragment to a parent it's not a child of." unless child.parent_id == self.id
|
445
|
+
child
|
446
|
+
else
|
386
447
|
existing = options.delete(:existing)
|
387
448
|
# root_id and parent_id are passed from parent to child. For all except root fragments, root_id is stored explicitly.
|
388
449
|
derived_options = {:root_id => root_id || id}
|
@@ -412,10 +473,7 @@ module Fragmentary
|
|
412
473
|
fragment_children = fragment.children
|
413
474
|
fragment.set_indexed_children if fragment.child_search_key
|
414
475
|
end
|
415
|
-
|
416
476
|
fragment
|
417
|
-
rescue => e
|
418
|
-
Rails.logger.error e.message + "\n " + e.backtrace.join("\n ")
|
419
477
|
end
|
420
478
|
end
|
421
479
|
|
@@ -436,7 +494,7 @@ module Fragmentary
|
|
436
494
|
end
|
437
495
|
|
438
496
|
def touch(*args, no_request: false)
|
439
|
-
request_queues.each{|key, queue| queue << request} if request && !no_request
|
497
|
+
request_queues.each{|key, hsh| hsh.each{|key2, queue| queue << request}} if request && !no_request
|
440
498
|
super(*args)
|
441
499
|
end
|
442
500
|
|
@@ -459,10 +517,13 @@ module Fragmentary
|
|
459
517
|
touch(:no_request => no_request) unless children.any?
|
460
518
|
end
|
461
519
|
|
520
|
+
# Touch this fragment and all descendants that have entries in the cache. Destroy any that
|
521
|
+
# don't have cache entries.
|
462
522
|
def touch_or_destroy
|
463
523
|
puts " touch_or_destroy #{self.class.name} #{id}"
|
464
524
|
if cache_exist?
|
465
525
|
children.each(&:touch_or_destroy)
|
526
|
+
# if there are children, this will be touched automatically once they are.
|
466
527
|
touch(:no_request => true) unless children.any?
|
467
528
|
else
|
468
529
|
destroy # will also destroy all children because of :dependent => :destroy
|
@@ -529,14 +590,6 @@ module Fragmentary
|
|
529
590
|
def needs_user_type?
|
530
591
|
true
|
531
592
|
end
|
532
|
-
|
533
|
-
def user_types
|
534
|
-
['admin', 'signed_in']
|
535
|
-
end
|
536
|
-
|
537
|
-
def user_type(user)
|
538
|
-
user ? (user.is_an_admin? ? "admin" : "signed_in") : "signed_out"
|
539
|
-
end
|
540
593
|
end
|
541
594
|
|
542
595
|
module NeedsKey
|
@@ -2,61 +2,76 @@ module Fragmentary
|
|
2
2
|
|
3
3
|
module FragmentsHelper
|
4
4
|
|
5
|
-
def cache_fragment(options)
|
6
|
-
|
7
|
-
|
8
|
-
fragment = options.delete(:fragment) || Fragmentary::Fragment.base_class.root(options)
|
9
|
-
builder = CacheBuilder.new(fragment, template = self)
|
10
|
-
unless no_cache
|
11
|
-
cache fragment, :skip_digest => true do
|
12
|
-
yield(builder)
|
13
|
-
end
|
14
|
-
else
|
15
|
-
yield(builder)
|
16
|
-
end
|
17
|
-
self.output_buffer = WidgetParser.new(self).parse_buffer
|
5
|
+
def cache_fragment(options, &block)
|
6
|
+
options.reverse_merge!(Fragmentary.config.application_root_url_column => self.root_url.gsub(%r{https?://}, ''))
|
7
|
+
CacheBuilder.new(self).cache_fragment(options, &block)
|
18
8
|
end
|
19
9
|
|
20
10
|
def fragment_builder(options)
|
21
|
-
template
|
22
|
-
options.
|
23
|
-
|
11
|
+
# the template option is deprecated but avoids breaking prior usage
|
12
|
+
template = options.delete(:template) || self
|
13
|
+
options.reverse_merge!(:user => Template.new(template).current_user)
|
14
|
+
options.reverse_merge!(Fragmentary.config.application_root_url_column => self.root_url.gsub(%r{https?://}, ''))
|
15
|
+
CacheBuilder.new(template, Fragmentary::Fragment.base_class.existing(options))
|
24
16
|
end
|
25
17
|
|
26
|
-
|
27
18
|
class CacheBuilder
|
28
19
|
include ::ActionView::Helpers::CacheHelper
|
29
20
|
include ::ActionView::Helpers::TextHelper
|
30
21
|
|
31
|
-
|
22
|
+
attr_reader :fragment
|
32
23
|
|
33
|
-
def initialize(
|
24
|
+
def initialize(template, fragment = nil)
|
34
25
|
@fragment = fragment
|
35
26
|
@template = template
|
36
27
|
end
|
37
28
|
|
38
|
-
def
|
29
|
+
def cache_fragment(options, &block)
|
39
30
|
no_cache = options.delete(:no_cache)
|
40
31
|
insert_widgets = options.delete(:insert_widgets)
|
41
|
-
options.reverse_merge!(:user => template
|
42
|
-
|
43
|
-
|
32
|
+
options.reverse_merge!(:user => Template.new(@template).current_user)
|
33
|
+
# If the CacheBuilder was instantiated with an existing fragment, next_fragment is its child;
|
34
|
+
# otherwise it is the root fragment specified by the options provided.
|
35
|
+
next_fragment = @fragment.try(:child, options) || Fragmentary::Fragment.base_class.root(options)
|
36
|
+
builder = CacheBuilder.new(@template, next_fragment)
|
44
37
|
unless no_cache
|
45
|
-
template.cache
|
38
|
+
@template.cache next_fragment, :skip_digest => true do
|
46
39
|
yield(builder)
|
47
40
|
end
|
48
41
|
else
|
49
42
|
yield(builder)
|
50
43
|
end
|
51
|
-
template.output_buffer = WidgetParser.new(template).parse_buffer if insert_widgets
|
44
|
+
@template.output_buffer = WidgetParser.new(@template).parse_buffer if (!@fragment || insert_widgets)
|
52
45
|
end
|
53
46
|
|
47
|
+
alias cache_child cache_fragment
|
48
|
+
|
49
|
+
private
|
50
|
+
|
54
51
|
def method_missing(method, *args)
|
55
|
-
fragment.send(method, *args)
|
52
|
+
@fragment.send(method, *args)
|
56
53
|
end
|
57
54
|
|
58
55
|
end
|
59
56
|
|
60
57
|
end
|
61
58
|
|
59
|
+
|
60
|
+
# Just a wrapper to allow us to call a configurable current_user_method on the template
|
61
|
+
class Template
|
62
|
+
|
63
|
+
def initialize(template)
|
64
|
+
@template = template
|
65
|
+
end
|
66
|
+
|
67
|
+
def current_user
|
68
|
+
return nil unless methd = Fragmentary.current_user_method
|
69
|
+
if @template.respond_to? methd
|
70
|
+
@template.send methd
|
71
|
+
else
|
72
|
+
raise NoMethodError, "The current_user_method '#{methd.to_s}' specified doesn't exist"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
62
77
|
end
|
@@ -33,7 +33,9 @@ module Fragmentary
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def after_update_broadcast
|
36
|
-
|
36
|
+
Rails.logger.info "\n***** #{start = Time.now} broadcasting :after_update from #{self.class.name} #{self.id}\n"
|
37
|
+
broadcast(:after_update, self) if self.previous_changes.any?
|
38
|
+
Rails.logger.info "\n***** #{Time.now} broadcast :after_update from #{self.class.name} #{self.id} took #{(Time.now - start) * 1000} ms\n"
|
37
39
|
end
|
38
40
|
|
39
41
|
def after_destroy_broadcast
|
data/lib/fragmentary/request.rb
CHANGED
@@ -3,28 +3,13 @@ module Fragmentary
|
|
3
3
|
class Request
|
4
4
|
attr_reader :method, :path, :options, :parameters
|
5
5
|
|
6
|
-
def initialize(method, path, parameters=nil, options=
|
6
|
+
def initialize(method, path, parameters=nil, options={})
|
7
7
|
@method, @path, @parameters, @options = method, path, parameters, options
|
8
8
|
end
|
9
9
|
|
10
10
|
def ==(other)
|
11
11
|
method == other.method and path == other.path and parameters == other.parameters and options == other.options
|
12
12
|
end
|
13
|
-
|
14
|
-
def to_proc
|
15
|
-
method = @method; path = @path; parameters = @parameters; options = @options.try :dup
|
16
|
-
if @options.try(:[], :xhr)
|
17
|
-
Proc.new do
|
18
|
-
puts " * Sending xhr request '#{method.to_s} #{path}'" + (!parameters.nil? ? " with #{parameters.inspect}" : "")
|
19
|
-
send(:xhr, method, path, parameters, options)
|
20
|
-
end
|
21
|
-
else
|
22
|
-
Proc.new do
|
23
|
-
puts " * Sending request '#{method.to_s} #{path}'" + (!parameters.nil? ? " with #{parameters.inspect}" : "")
|
24
|
-
send(method, path, parameters, options)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
13
|
end
|
29
14
|
|
30
15
|
end
|