interlock 1.0 → 1.1

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.
Files changed (40) hide show
  1. data/CHANGELOG +2 -0
  2. data/Manifest +8 -15
  3. data/README +16 -73
  4. data/TODO +3 -0
  5. data/interlock.gemspec +16 -9
  6. data/lib/interlock/action_controller.rb +135 -36
  7. data/lib/interlock/action_view.rb +85 -18
  8. data/lib/interlock/active_record.rb +1 -1
  9. data/lib/interlock/config.rb +1 -1
  10. data/lib/interlock/interlock.rb +22 -3
  11. data/tasks/interlock.rake +10 -0
  12. data/test/integration/app/app/controllers/application.rb +2 -2
  13. data/test/integration/app/app/controllers/items_controller.rb +19 -1
  14. data/test/integration/app/app/views/items/detail.rhtml +20 -0
  15. data/test/integration/app/app/views/items/{list.html.erb → list.rhtml} +6 -0
  16. data/test/integration/app/app/views/items/{recent.html.erb → recent.rhtml} +0 -0
  17. data/test/integration/app/app/views/items/{show.html.erb → show.rhtml} +1 -1
  18. data/test/integration/app/app/views/layouts/application.html.erb +9 -0
  19. data/test/integration/app/app/views/shared/{_related.html.erb → _related.rhtml} +0 -0
  20. data/test/integration/app/config/boot.rb +2 -0
  21. data/test/integration/app/config/environment.rb +1 -3
  22. data/test/integration/server_test.rb +53 -6
  23. data/test/setup.rb +5 -0
  24. data/test/teardown.rb +0 -4
  25. data/test/test_helper.rb +9 -2
  26. data/test/unit/interlock_test.rb +21 -0
  27. data.tar.gz.sig +0 -0
  28. metadata +14 -20
  29. metadata.gz.sig +0 -0
  30. data/test/integration/app/coverage/cache-43041 +0 -0
  31. data/test/integration/app/coverage/index.html +0 -414
  32. data/test/integration/app/coverage/vendor-plugins-interlock-lib-interlock-action_controller_rb.html +0 -733
  33. data/test/integration/app/coverage/vendor-plugins-interlock-lib-interlock-action_view_rb.html +0 -644
  34. data/test/integration/app/coverage/vendor-plugins-interlock-lib-interlock-active_record_rb.html +0 -639
  35. data/test/integration/app/coverage/vendor-plugins-interlock-lib-interlock-config_rb.html +0 -688
  36. data/test/integration/app/coverage/vendor-plugins-interlock-lib-interlock-core_extensions_rb.html +0 -674
  37. data/test/integration/app/coverage/vendor-plugins-interlock-lib-interlock-interlock_rb.html +0 -722
  38. data/test/integration/app/coverage/vendor-plugins-interlock-lib-interlock-memcached_rb.html +0 -640
  39. data/test/integration/app/coverage/vendor-plugins-interlock-lib-interlock_rb.html +0 -635
  40. data/test/integration/app/db/schema.rb +0 -21
@@ -19,7 +19,7 @@ module Interlock
19
19
  #
20
20
  # Load the configuration file, if available, and then set up the Memcached instance,
21
21
  # Rails settings, and CACHE constants. Should be more or less compatible with
22
- # cache_fu.
22
+ # Cache_fu.
23
23
  #
24
24
  def run!
25
25
  if File.exist?(CONFIG_FILE)
@@ -7,9 +7,20 @@ module Interlock
7
7
  end
8
8
  class UsageError < InterlockError #:nodoc:
9
9
  end
10
+ class FragmentConsistencyError < InterlockError #:nodoc:
11
+ end
10
12
 
11
13
  SCOPE_KEYS = [:controller, :action, :id]
12
14
 
15
+ # Buried value extracted from memcache.rb in the memcache-client gem.
16
+ # If one tries to request a key that is too long, the client throws an error.
17
+ # In practice, it seems better to simply avoid ever setting such long keys,
18
+ # so we use this value to achieve such for keys generated by Interlock.
19
+ KEY_LENGTH_LIMIT = 250
20
+
21
+ # Similarly buried and useful: no whitespace allowed in keys.
22
+ ILLEGAL_KEY_CHARACTERS_PATTERN = /\s/
23
+
13
24
  mattr_accessor :local_cache
14
25
 
15
26
  class << self
@@ -93,12 +104,20 @@ module Interlock
93
104
  # rolling your own.
94
105
  #
95
106
  def caching_key(controller, action, id, tag)
96
- raise ArgumentError, "Both controller and action must be specified" unless controller and action
107
+ raise ArgumentError, 'Both controller and action must be specified' unless controller and action
97
108
 
98
109
  id = (id or 'all').to_interlock_tag
99
110
  tag = tag.to_interlock_tag
100
-
101
- "interlock:#{ENV['RAILS_ASSET_ID']}:#{controller}:#{action}:#{id}:#{tag}"
111
+
112
+ key = "interlock:#{ENV['RAILS_ASSET_ID']}:#{controller}:#{action}:#{id}:#{tag}"
113
+
114
+ if key.length > KEY_LENGTH_LIMIT
115
+ old_key = key
116
+ key = key[0..KEY_LENGTH_LIMIT-1]
117
+ say old_key, "truncated to #{key}"
118
+ end
119
+
120
+ key.gsub ILLEGAL_KEY_CHARACTERS_PATTERN, ''
102
121
  end
103
122
 
104
123
  #
@@ -0,0 +1,10 @@
1
+
2
+ namespace :interlock do
3
+ desc "Watch the Rails log for Interlock-specific messages"
4
+ task :tail do
5
+ Dir.chdir RAILS_ROOT do
6
+ exec("tail -f log/#{RAILS_ENV}.log | grep interlock")
7
+ end
8
+ end
9
+ end
10
+
@@ -2,9 +2,9 @@
2
2
  # Likewise, all the methods added will be available for all controllers.
3
3
 
4
4
  class ApplicationController < ActionController::Base
5
- helper :all # include all helpers, all the time
5
+ # helper :all # include all helpers, all the time
6
6
 
7
7
  # See ActionController::RequestForgeryProtection for details
8
8
  # Uncomment the :secret if you're not using the cookie session store
9
- protect_from_forgery # :secret => '491bb7f9ad07a91046fcc3756839524b'
9
+ # protect_from_forgery # :secret => '491bb7f9ad07a91046fcc3756839524b'
10
10
  end
@@ -9,6 +9,16 @@ class ItemsController < ApplicationController
9
9
  render :action => 'list'
10
10
  end
11
11
 
12
+ def detail
13
+ # Nesting is theoretically useful when the outer view block invalidates faster than the inner one
14
+ behavior_cache :tag => :outer do
15
+ @items = Item.find(:all)
16
+ end
17
+ behavior_cache Item => :id, :tag => :inner do
18
+ @item = Item.find(params[:id])
19
+ end
20
+ end
21
+
12
22
  def show
13
23
  behavior_cache Item => :id do
14
24
  @item = Item.find(params['id'])
@@ -21,6 +31,14 @@ class ItemsController < ApplicationController
21
31
  end
22
32
  end
23
33
 
34
+ def preview
35
+ @perform = false
36
+ behavior_cache Item => :id, :perform => @perform do
37
+ @item = Item.find(params['id'])
38
+ end
39
+ render :action => 'show'
40
+ end
41
+
24
42
  private
25
43
 
26
44
  def related
@@ -28,5 +46,5 @@ class ItemsController < ApplicationController
28
46
  @related = "Delicious cake"
29
47
  end
30
48
  end
31
-
49
+
32
50
  end
@@ -0,0 +1,20 @@
1
+
2
+ <% view_cache :tag => :outer do %>
3
+ <div style="border: 1px solid black; padding: 5px;">
4
+ <p>I invalidate quickly.</p>
5
+ <h1><%= @items.size %> total items</h1>
6
+
7
+ <% content_for :title do %>Outer: <% end %>
8
+
9
+ <% view_cache :tag => :inner do %>
10
+ <div style="margin: 20px; padding: 5px; border: 1px solid black;">
11
+ <p>I invalidate slowly.</p>
12
+ <h2>Item <%= @item.id %> is <%= @item.name %>.</h2>
13
+
14
+ <% content_for :title do %>Inner<% end %>
15
+
16
+ </div>
17
+ <% end %>
18
+
19
+ </div>
20
+ <% end %>
@@ -1,10 +1,16 @@
1
1
 
2
2
  <h1>List</h1>
3
3
  <% view_cache do %>
4
+
5
+ <% content_for :title do %>
6
+ <%= @items.size %> Items
7
+ <% end %>
8
+
4
9
  <% @items.each do |item| %>
5
10
  <h3><%= item.name %></h3>
6
11
  <p><%= item.description %></p>
7
12
  <% end %>
13
+
8
14
  <% end %>
9
15
 
10
16
  <%= render :partial => 'shared/related' %>
@@ -1,6 +1,6 @@
1
1
 
2
2
  <h1>Show</h1>
3
- <% view_cache Item => :id do %>
3
+ <% view_cache :perform => @perform do %>
4
4
  <h3><%= @item.name %></h3>
5
5
  <p><%= @item.description %></p>
6
6
  <% end %>
@@ -0,0 +1,9 @@
1
+ <html>
2
+ <head>
3
+ <title>Interlock Test: <%= yield :title %></title>
4
+ </head>
5
+ <body>
6
+ <%= yield %>
7
+ </body>
8
+ </html>
9
+
@@ -55,8 +55,10 @@ module Rails
55
55
 
56
56
  def load_rails_gem
57
57
  if version = self.class.gem_version
58
+ STDERR.puts "Boot.rb loading version #{version}"
58
59
  gem 'rails', version
59
60
  else
61
+ STDERR.puts "Boot.rb loading latest available version"
60
62
  gem 'rails'
61
63
  end
62
64
  rescue Gem::LoadError => load_error
@@ -1,13 +1,11 @@
1
1
 
2
- RAILS_GEM_VERSION = ENV['MULTIRAILS_RAILS_VERSION'] if ENV['MULTIRAILS_RAILS_VERSION']
3
-
4
2
  require File.join(File.dirname(__FILE__), 'boot')
5
3
  require 'action_controller'
6
4
 
7
5
  Rails::Initializer.run do |config|
8
6
 
9
7
  if ActionController::Base.respond_to? 'session='
10
- config.action_controller.session = {:session_key => '_app_session', :secret => '22cde4d5c1a61ba69a817953'}
8
+ config.action_controller.session = {:session_key => '_app_session', :secret => '22cde4d5c1a61ba69a81795322cde4d5c1a61ba69a817953'}
11
9
  end
12
10
 
13
11
  # config.to_prepare do
@@ -70,7 +70,8 @@ class ServerTest < Test::Unit::TestCase
70
70
  end
71
71
 
72
72
  def test_caching_with_tag
73
- sleep(3)
73
+ # This test is a little over-complicated
74
+ sleep(4)
74
75
  assert_no_match(/Artichoke/, browse("items/recent?seconds=3"))
75
76
  assert_match(/recent:all:3 is running the controller block/, log)
76
77
 
@@ -79,15 +80,26 @@ class ServerTest < Test::Unit::TestCase
79
80
  assert_match(/recent:all:2 is running the controller block/, log)
80
81
  assert_no_match(/recent:all:3 is running the controller block/, log)
81
82
 
83
+ truncate
84
+ remote_eval("Item.find(1).save!")
85
+ assert_match(/Artichoke/, browse("items/recent?seconds=4"))
86
+ assert_match(/recent:all:4 is running the controller block/, log)
87
+
82
88
  truncate
83
89
  assert_no_match(/Artichoke/, browse("items/recent?seconds=3"))
84
- assert_no_match(/recent:all:3 is running the controller block/, log)
90
+ assert_no_match(/recent:all:3 is running the controller block/, log)
91
+ end
92
+
93
+ def test_caching_with_perform_false
94
+ browse("items/preview/1")
95
+ assert_no_match(/preview:1:untagged registered a dependency/, log)
96
+ assert_match(/preview:1:untagged is not cached/, log)
85
97
 
86
98
  truncate
87
- remote_eval("Item.find(1).save!")
88
- assert_match(/Artichoke/, browse("items/recent?seconds=3"))
89
- assert_match(/recent:all:3 is running the controller block/, log)
90
- end
99
+ browse("items/preview/1")
100
+ assert_no_match(/preview:1:untagged registered a dependency/, log)
101
+ assert_match(/preview:1:untagged is not cached/, log)
102
+ end
91
103
 
92
104
  def test_caching_with_ignore
93
105
  assert_match(/Delicious cake/, browse('items'))
@@ -104,6 +116,41 @@ class ServerTest < Test::Unit::TestCase
104
116
  assert_match(/any:any:all:related is running the controller block/, log)
105
117
  end
106
118
 
119
+ def test_caching_of_content_for
120
+ assert_match(/Interlock Test:\s*\d\s*Items/m, browse("items"))
121
+ assert_match(/all:untagged is running the controller block/, log)
122
+ assert_match(/all:untagged wrote/, log)
123
+
124
+ truncate
125
+ assert_match(/Interlock Test:\s*\d\s*Items/m, browse("items"))
126
+ # Make sure we didn't copy the content_for too many times
127
+ assert_no_match(/Interlock Test:\s*\d\s*Items\s*\d\s*Items/m, browse("items"))
128
+ assert_no_match(/all:untagged is running the controller block/, log)
129
+ assert_match(/all:untagged read from memcached/, log)
130
+ end
131
+
132
+ def test_nested_view_caches
133
+ assert_match(/Outer: Inner<.*2 total items.*Artichoke/m, browse("items/detail/1"))
134
+ assert_match(/detail:1:outer is running the controller block/, log)
135
+ assert_match(/detail:1:inner is running the controller block/, log)
136
+
137
+ truncate
138
+ assert_match(/Outer: Inner<.*2 total items.*Artichoke/m, browse("items/detail/1"))
139
+ assert_no_match(/detail:1:outer is running the controller block/, log)
140
+ assert_no_match(/detail:1:inner is running the controller block/, log)
141
+
142
+ truncate
143
+ remote_eval("Item.find(2).save!")
144
+ assert_match(/Outer: Inner<.*2 total items.*Artichoke/m, browse("items/detail/1"))
145
+ assert_match(/detail:1:outer is running the controller block/, log)
146
+ assert_no_match(/detail:1:inner is running the controller block/, log)
147
+
148
+ truncate
149
+ remote_eval("Item.find(1).save!")
150
+ assert_match(/Outer: Inner<.*2 total items.*Artichoke/m, browse("items/detail/1"))
151
+ assert_match(/detail:1:outer is running the controller block/, log)
152
+ assert_match(/detail:1:inner is running the controller block/, log)
153
+ end
107
154
 
108
155
  ### Support methods
109
156
 
data/test/setup.rb CHANGED
@@ -2,6 +2,11 @@
2
2
  # Setup integration system for the integration suite
3
3
 
4
4
  Dir.chdir "#{File.dirname(__FILE__)}/integration/app/" do
5
+
6
+ `ps awx`.split("\n").grep(/4304[1-3]/).map do |process|
7
+ system("kill -9 #{process.to_i}")
8
+ end
9
+
5
10
  system "memcached -p 43042 &"
6
11
  system "memcached -p 43043 &"
7
12
 
data/test/teardown.rb CHANGED
@@ -1,4 +0,0 @@
1
-
2
- `ps awx`.split("\n").grep(/4304[1-3]/).map do |process|
3
- system("kill -9 #{process.to_i}")
4
- end
data/test/test_helper.rb CHANGED
@@ -2,12 +2,19 @@
2
2
  $VERBOSE = nil
3
3
  require 'rubygems'
4
4
  require 'test/unit'
5
+ require 'echoe'
5
6
  require 'multi_rails_init'
6
7
 
8
+ if defined? ENV['MULTIRAILS_RAILS_VERSION']
9
+ ENV['RAILS_GEM_VERSION'] = ENV['MULTIRAILS_RAILS_VERSION']
10
+ end
11
+
7
12
  $rcov = ENV['RCOV']
8
13
  require 'ruby-debug' unless $rcov
9
14
 
10
- HERE = File.expand_path(File.dirname(__FILE__))
11
- $LOAD_PATH << HERE
15
+ Echoe.silence do
16
+ HERE = File.expand_path(File.dirname(__FILE__))
17
+ $LOAD_PATH << HERE
18
+ end
12
19
 
13
20
  require 'integration/app/config/environment'
@@ -0,0 +1,21 @@
1
+ require "#{File.dirname(__FILE__)}/../test_helper"
2
+
3
+ class InterlockTest < Test::Unit::TestCase
4
+ def test_caching_key_requires_controller_and_action
5
+ assert_raises ArgumentError do
6
+ Interlock.caching_key nil, nil, nil, nil
7
+ end
8
+ end
9
+
10
+ def test_caching_key_prevents_too_long_keys
11
+ assert_equal Interlock::KEY_LENGTH_LIMIT,
12
+ Interlock.caching_key('controller', 'action', 'id', 'x'*Interlock::KEY_LENGTH_LIMIT).size,
13
+ "keys longer than #{Interlock::KEY_LENGTH_LIMIT} will result in errors from memcache-client"
14
+ end
15
+
16
+ def test_caching_key_strips_whitespace
17
+ assert_no_match Interlock::ILLEGAL_KEY_CHARACTERS_PATTERN,
18
+ Interlock.caching_key('controller', 'action', 'id', 'tag with illegal characters')
19
+ 'generated keys should not contain illegal characters'
20
+ end
21
+ end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: interlock
3
3
  version: !ruby/object:Gem::Version
4
- version: "1.0"
4
+ version: "1.1"
5
5
  platform: ruby
6
6
  authors:
7
7
  - ""
@@ -30,7 +30,7 @@ cert_chain:
30
30
  yZ0=
31
31
  -----END CERTIFICATE-----
32
32
 
33
- date: 2007-12-13 00:00:00 -05:00
33
+ date: 2008-01-15 00:00:00 -05:00
34
34
  default_executable:
35
35
  dependencies:
36
36
  - !ruby/object:Gem::Dependency
@@ -42,7 +42,7 @@ dependencies:
42
42
  - !ruby/object:Gem::Version
43
43
  version: 1.5.0
44
44
  version:
45
- description: An optimal-efficiency caching plugin for Rails.
45
+ description: A Rails plugin for maintainable and high-efficiency caching.
46
46
  email: ""
47
47
  executables: []
48
48
 
@@ -65,6 +65,7 @@ files:
65
65
  - LICENSE
66
66
  - Manifest
67
67
  - README
68
+ - tasks/interlock.rake
68
69
  - test/integration/app/app/controllers/application.rb
69
70
  - test/integration/app/app/controllers/eval_controller.rb
70
71
  - test/integration/app/app/controllers/items_controller.rb
@@ -72,10 +73,12 @@ files:
72
73
  - test/integration/app/app/helpers/eval_helper.rb
73
74
  - test/integration/app/app/helpers/items_helper.rb
74
75
  - test/integration/app/app/models/item.rb
75
- - test/integration/app/app/views/items/list.html.erb
76
- - test/integration/app/app/views/items/recent.html.erb
77
- - test/integration/app/app/views/items/show.html.erb
78
- - test/integration/app/app/views/shared/_related.html.erb
76
+ - test/integration/app/app/views/items/detail.rhtml
77
+ - test/integration/app/app/views/items/list.rhtml
78
+ - test/integration/app/app/views/items/recent.rhtml
79
+ - test/integration/app/app/views/items/show.rhtml
80
+ - test/integration/app/app/views/layouts/application.html.erb
81
+ - test/integration/app/app/views/shared/_related.rhtml
79
82
  - test/integration/app/config/boot.rb
80
83
  - test/integration/app/config/database.yml
81
84
  - test/integration/app/config/environment.rb
@@ -86,18 +89,7 @@ files:
86
89
  - test/integration/app/config/initializers/mime_types.rb
87
90
  - test/integration/app/config/memcached.yml
88
91
  - test/integration/app/config/routes.rb
89
- - test/integration/app/coverage/cache-43041
90
- - test/integration/app/coverage/index.html
91
- - test/integration/app/coverage/vendor-plugins-interlock-lib-interlock-action_controller_rb.html
92
- - test/integration/app/coverage/vendor-plugins-interlock-lib-interlock-action_view_rb.html
93
- - test/integration/app/coverage/vendor-plugins-interlock-lib-interlock-active_record_rb.html
94
- - test/integration/app/coverage/vendor-plugins-interlock-lib-interlock-config_rb.html
95
- - test/integration/app/coverage/vendor-plugins-interlock-lib-interlock-core_extensions_rb.html
96
- - test/integration/app/coverage/vendor-plugins-interlock-lib-interlock-interlock_rb.html
97
- - test/integration/app/coverage/vendor-plugins-interlock-lib-interlock-memcached_rb.html
98
- - test/integration/app/coverage/vendor-plugins-interlock-lib-interlock_rb.html
99
92
  - test/integration/app/db/migrate/001_create_items.rb
100
- - test/integration/app/db/schema.rb
101
93
  - test/integration/app/doc/README_FOR_APP
102
94
  - test/integration/app/public/404.html
103
95
  - test/integration/app/public/422.html
@@ -138,6 +130,7 @@ files:
138
130
  - test/setup.rb
139
131
  - test/teardown.rb
140
132
  - test/test_helper.rb
133
+ - test/unit/interlock_test.rb
141
134
  - test/unit/memcached_test.rb
142
135
  - TODO
143
136
  - interlock.gemspec
@@ -163,10 +156,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
163
156
  requirements: []
164
157
 
165
158
  rubyforge_project: fauna
166
- rubygems_version: 0.9.5
159
+ rubygems_version: 1.0.1
167
160
  signing_key:
168
161
  specification_version: 2
169
- summary: An optimal-efficiency caching plugin for Rails.
162
+ summary: A Rails plugin for maintainable and high-efficiency caching.
170
163
  test_files:
171
164
  - test/integration/server_test.rb
165
+ - test/unit/interlock_test.rb
172
166
  - test/unit/memcached_test.rb
metadata.gz.sig CHANGED
Binary file