timestamper 0.0.2

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.
@@ -0,0 +1,14 @@
1
+ README.rdoc
2
+ Rakefile
3
+ lib/timestamper.rb
4
+ lib/timestamper/activeresource.rb
5
+ lib/timestamper/configuration.rb
6
+ lib/timestamper/rack_middleware.rb
7
+ lib/timestamper/timestamper.rb
8
+ spec/fixtures.rb
9
+ spec/lib_specs/activeresource_spec.rb
10
+ spec/lib_specs/configuration_spec.rb
11
+ spec/lib_specs/rack_spec.rb
12
+ spec/lib_specs/timestamper_spec.rb
13
+ spec/spec_helper.rb
14
+ Manifest
@@ -0,0 +1,16 @@
1
+ = Use
2
+
3
+ Timestamper allows you to automatically set http response's header Last-Modified with value from ActiveResource or ActiveRecord. Currently only supports ActiveResource.
4
+
5
+ = Configuration
6
+
7
+ Timestamper.config do
8
+ updated_at_column :updated_at # global default column
9
+ end
10
+
11
+ class Article
12
+ timestamper_column :last_modified # custom timestamp column
13
+ end
14
+
15
+ To configure rack middleware in a Rails app, add following line to config/environment.rb.
16
+ ActionController::Dispatcher.middleware.use Timestamper::RackMiddleware
@@ -0,0 +1,12 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'echoe'
4
+
5
+ Echoe.new('timestamper', '0.0.2') do |p|
6
+ p.description = "This gem sets Last-Modified in http response header with timestamp extracted from ActiveResource."
7
+ p.url = "http://github.com/dorren/timestamper"
8
+ p.author = "Dorren Chen"
9
+ p.email = "dorrenchen@gmail.com"
10
+ p.ignore_pattern = ["tmp/*", "script/*"]
11
+ p.development_dependencies = []
12
+ end
@@ -0,0 +1,6 @@
1
+ require 'singleton'
2
+ require 'activeresource'
3
+ require 'timestamper/timestamper'
4
+ require 'timestamper/activeresource'
5
+ require 'timestamper/configuration'
6
+ require 'timestamper/rack_middleware'
@@ -0,0 +1,21 @@
1
+ module ActiveResource
2
+ class Base
3
+ class << self
4
+ def timestamper_column(column)
5
+ @timestamper_column = column
6
+ end
7
+
8
+ private
9
+ def new_with_timestamper(*args)
10
+ returning new_without_timestamper(*args) do |record|
11
+ next if !Timestamper.configuration.reportable?(record.class) # return triggers "LocalJumpError: unexpected return"
12
+
13
+ column = @timestamper_column || Timestamper.configuration.updated_at_column
14
+ Timestamper.instance.updated_at = record.send(column) if record.respond_to?(column)
15
+ end
16
+ end
17
+
18
+ alias_method_chain :new, :timestamper
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,37 @@
1
+ class Timestamper
2
+ class Configuration
3
+ attr_accessor :updated_at_column
4
+
5
+ def initialize
6
+ @updated_at_column = :updated_at
7
+ @exclude = []
8
+ @only = []
9
+ end
10
+
11
+ def exclude(*args)
12
+ @exclude += args
13
+ end
14
+
15
+ def excluded_models
16
+ @exclude.dup
17
+ end
18
+
19
+ def only(*args)
20
+ @only += args
21
+ end
22
+
23
+ def only_models
24
+ @only.dup
25
+ end
26
+
27
+ def reportable?(klass)
28
+ return true if @exclude.empty? and @only.empty?
29
+
30
+ if @only.empty?
31
+ !@exclude.include?(klass)
32
+ else
33
+ (@only - @exclude).include?(klass)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,24 @@
1
+ class Timestamper
2
+ class RackMiddleware
3
+ def initialize(app)
4
+ @app = app
5
+ end
6
+
7
+ def call(env)
8
+ Timestamper.instance.reset
9
+ status, headers, response = @app.call(env)
10
+ if headers["Content-Type"].to_s =~ /^text\/html/
11
+
12
+ if status == 200 and headers['Last-Modified'].nil?
13
+ timestamp = Timestamper.instance.updated_at || Time.now
14
+ headers['Last-Modified'] = timestamp.httpdate
15
+ end
16
+ # rails return response object with body method, sinatra just returns array of 1 string
17
+ response = response.respond_to?(:body) ? response.body : response
18
+ [status, headers, response]
19
+ else
20
+ [status, headers, response]
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,26 @@
1
+
2
+ class Timestamper
3
+ include Singleton
4
+ attr_accessor :updated_at, :override
5
+
6
+ def reset
7
+ @override = nil
8
+ @updated_at = nil
9
+ end
10
+
11
+ def updated_at
12
+ @override ? @override : @updated_at
13
+ end
14
+
15
+ def updated_at=(time)
16
+ @updated_at = time if self.updated_at.nil? or time > self.updated_at
17
+ end
18
+
19
+ def self.configuration
20
+ @configuration ||= Configuration.new
21
+ end
22
+
23
+ def self.config(&block)
24
+ configuration.instance_eval(&block)
25
+ end
26
+ end
@@ -0,0 +1,8 @@
1
+
2
+ # testing fixtures
3
+ class Content < ActiveResource::Base
4
+ self.site = ""
5
+ end
6
+ class Article < Content; end
7
+ class Page < Content; end
8
+ class Comment < Content; end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveResource::Base do
4
+ before do
5
+ @today = Time.now
6
+ @yesterday = 1.day.ago
7
+ @tomorrow = 1.day.from_now
8
+ Timestamper.instance.reset
9
+ end
10
+
11
+ describe "#new" do
12
+ it "should report updated_at time" do
13
+ Timestamper.instance.updated_at.should be_nil
14
+ Article.new :updated_at => @today
15
+ Timestamper.instance.updated_at.should == @today
16
+ end
17
+ end
18
+
19
+ describe "#new_with_timestamper" do
20
+ it "should not set time if class is not reportable" do
21
+ class Draft < Content; end
22
+
23
+ Timestamper.instance.updated_at.should be_nil
24
+ Timestamper.configuration.exclude Draft
25
+ Draft.new :updated_at => @today
26
+ Timestamper.instance.updated_at.should be_nil
27
+ end
28
+ end
29
+
30
+ describe "##timestamper_column" do
31
+ class MyArticle < Content; end
32
+ it "should set timestamper_column" do
33
+ MyArticle.class_eval do
34
+ timestamper_column :last_modified
35
+ end
36
+ Timestamper.instance.updated_at.should be_nil
37
+ MyArticle.new :last_modified => @today
38
+ Timestamper.instance.updated_at.should == @today
39
+ end
40
+ end
41
+
42
+ end
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+
3
+ describe Timestamper::Configuration do
4
+ before(:each) do
5
+ @config = Timestamper::Configuration.new
6
+ end
7
+
8
+ describe "#exclude" do
9
+ it "should exclude selected models" do
10
+ @config.exclude Article, Page
11
+ @config.excluded_models.should == [Article, Page]
12
+ end
13
+ end
14
+
15
+ describe "#only" do
16
+ it "should only have selected models" do
17
+ @config.only Article
18
+ @config.only_models.should == [Article]
19
+ end
20
+ end
21
+
22
+ describe "#reportable?" do
23
+ it "should query whether model is reportable?" do
24
+ @config.reportable?(Article).should be_true
25
+
26
+ @config.only Article
27
+ @config.reportable?(Article).should be_true
28
+ @config.reportable?(Page).should be_false
29
+
30
+ @config.exclude Article
31
+ @config.reportable?(Article).should be_false
32
+ @config.reportable?(Page).should be_false
33
+
34
+ @config = Timestamper::Configuration.new
35
+ @config.exclude Article
36
+ @config.reportable?(Article).should be_false
37
+ @config.reportable?(Page).should be_true
38
+
39
+ @config.only Article
40
+ @config.reportable?(Article).should be_false
41
+ @config.reportable?(Page).should be_false
42
+ end
43
+ end
44
+
45
+ describe "#updated_at_column" do
46
+ it "should set updated_at_column" do
47
+ @config.updated_at_column = :updated_at
48
+ @config.updated_at_column.should == :updated_at
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+ require 'rack/test'
3
+ require 'sinatra/base'
4
+ require 'timestamper/rack_middleware'
5
+ require 'active_resource/http_mock'
6
+
7
+ class MyApp < Sinatra::Base
8
+ use Timestamper::RackMiddleware
9
+
10
+ get "/" do
11
+ "homepage"
12
+ end
13
+
14
+ get "/articles" do
15
+ @article1 = Article.find 1
16
+ 'articles'
17
+ end
18
+ end
19
+
20
+ describe Timestamper::RackMiddleware do
21
+ include Rack::Test::Methods
22
+ before(:each) do
23
+ @today = Time.now
24
+ @yesterday = 1.day.ago
25
+ @tomorrow = 1.day.from_now
26
+ Timestamper.instance.reset
27
+
28
+ ActiveResource::HttpMock.respond_to do |mock|
29
+ mock.get "/articles/1.xml", {}, {:id => 1, :updated_at => @yesterday}.to_xml(:root => "article")
30
+ end
31
+ end
32
+
33
+ def app
34
+ my_app = MyApp.new
35
+ end
36
+
37
+ def log_response_body(str)
38
+ File.open('response.html', 'w') do |f|
39
+ f.write str
40
+ end
41
+ end
42
+
43
+ it "should have default Last-Modified http header" do
44
+ get "/"
45
+ last_response.body.should == "homepage"
46
+ last_response.headers["Last-Modified"].should_not be_nil
47
+ end
48
+
49
+ it "should set Last-Modified time from article" do
50
+ get "/articles"
51
+ last_response.body.should == "articles"
52
+ last_response.headers["Last-Modified"].should == @yesterday.httpdate
53
+ end
54
+ end
@@ -0,0 +1,78 @@
1
+
2
+
3
+ describe Timestamper do
4
+ before do
5
+ @today = Time.now
6
+ @yesterday = 1.day.ago
7
+ @tomorrow = 1.day.from_now
8
+ Timestamper.instance.reset
9
+ end
10
+
11
+ describe "#instance" do
12
+ it "should implement singleton pattern" do
13
+ proc {Timestamper.new}.should raise_error
14
+ proc {Timestamper.instance}.should_not raise_error
15
+ end
16
+ end
17
+
18
+ describe "#reset" do
19
+ it "should reset itself" do
20
+ Timestamper.instance.updated_at = @today
21
+ Timestamper.instance.override = @yesterday
22
+ Timestamper.instance.reset
23
+ Timestamper.instance.updated_at.should be_nil
24
+ Timestamper.instance.override.should be_nil
25
+ end
26
+ end
27
+
28
+ describe "#update_at" do
29
+ it "should be able to set updated_at time" do
30
+ Timestamper.instance.updated_at.should be_nil
31
+ Timestamper.instance.updated_at = @today
32
+ Timestamper.instance.updated_at.should == @today
33
+ end
34
+
35
+ it "should only change updated_at time if the new value is the latest time" do
36
+ Timestamper.instance.updated_at = @tomorrow
37
+ Timestamper.instance.updated_at = @today
38
+ Timestamper.instance.updated_at.should == @tomorrow
39
+ end
40
+ end
41
+
42
+ describe "#override" do
43
+ it "should override current updated_at value when updated_at is nil" do
44
+ Timestamper.instance.updated_at.should be_nil
45
+ Timestamper.instance.override = @today
46
+ Timestamper.instance.updated_at.should == @today
47
+ end
48
+
49
+ it "should override current updated_at value" do
50
+ Timestamper.instance.updated_at = @tomorrow
51
+ Timestamper.instance.override = @today
52
+ Timestamper.instance.updated_at.should == @today
53
+
54
+ Timestamper.instance.updated_at = @today + 2.days
55
+ Timestamper.instance.updated_at.should == @today
56
+ end
57
+ end
58
+
59
+ describe "##configuration" do
60
+ it "should return an instance of Timestamper::Configuration" do
61
+ Timestamper.configuration.class.should == Timestamper::Configuration
62
+ end
63
+ end
64
+
65
+
66
+
67
+ describe "##config" do
68
+ it "should accept a block" do
69
+ proc {Timestamper.config {}}.should_not raise_error
70
+ end
71
+
72
+ it "should evaluate the block within the Timestamper.configuration instance" do
73
+ Timestamper.config do
74
+ self.should == Timestamper.configuration
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,3 @@
1
+ $LOAD_PATH << './lib'
2
+ require 'timestamper'
3
+ require 'fixtures'
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{timestamper}
5
+ s.version = "0.0.2"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Dorren Chen"]
9
+ s.date = %q{2010-04-14}
10
+ s.description = %q{This gem sets Last-Modified in http response header with timestamp extracted from ActiveResource.}
11
+ s.email = %q{dorrenchen@gmail.com}
12
+ s.extra_rdoc_files = ["README.rdoc", "lib/timestamper.rb", "lib/timestamper/activeresource.rb", "lib/timestamper/configuration.rb", "lib/timestamper/rack_middleware.rb", "lib/timestamper/timestamper.rb"]
13
+ s.files = ["README.rdoc", "Rakefile", "lib/timestamper.rb", "lib/timestamper/activeresource.rb", "lib/timestamper/configuration.rb", "lib/timestamper/rack_middleware.rb", "lib/timestamper/timestamper.rb", "spec/fixtures.rb", "spec/lib_specs/activeresource_spec.rb", "spec/lib_specs/configuration_spec.rb", "spec/lib_specs/rack_spec.rb", "spec/lib_specs/timestamper_spec.rb", "spec/spec_helper.rb", "Manifest", "timestamper.gemspec"]
14
+ s.homepage = %q{http://github.com/dorren/timestamper}
15
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Timestamper", "--main", "README.rdoc"]
16
+ s.require_paths = ["lib"]
17
+ s.rubyforge_project = %q{timestamper}
18
+ s.rubygems_version = %q{1.3.6}
19
+ s.summary = %q{This gem sets Last-Modified in http response header with timestamp extracted from ActiveResource.}
20
+
21
+ if s.respond_to? :specification_version then
22
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
23
+ s.specification_version = 3
24
+
25
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
26
+ else
27
+ end
28
+ else
29
+ end
30
+ end
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: timestamper
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 2
9
+ version: 0.0.2
10
+ platform: ruby
11
+ authors:
12
+ - Dorren Chen
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-04-14 00:00:00 -04:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: This gem sets Last-Modified in http response header with timestamp extracted from ActiveResource.
22
+ email: dorrenchen@gmail.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files:
28
+ - README.rdoc
29
+ - lib/timestamper.rb
30
+ - lib/timestamper/activeresource.rb
31
+ - lib/timestamper/configuration.rb
32
+ - lib/timestamper/rack_middleware.rb
33
+ - lib/timestamper/timestamper.rb
34
+ files:
35
+ - README.rdoc
36
+ - Rakefile
37
+ - lib/timestamper.rb
38
+ - lib/timestamper/activeresource.rb
39
+ - lib/timestamper/configuration.rb
40
+ - lib/timestamper/rack_middleware.rb
41
+ - lib/timestamper/timestamper.rb
42
+ - spec/fixtures.rb
43
+ - spec/lib_specs/activeresource_spec.rb
44
+ - spec/lib_specs/configuration_spec.rb
45
+ - spec/lib_specs/rack_spec.rb
46
+ - spec/lib_specs/timestamper_spec.rb
47
+ - spec/spec_helper.rb
48
+ - Manifest
49
+ - timestamper.gemspec
50
+ has_rdoc: true
51
+ homepage: http://github.com/dorren/timestamper
52
+ licenses: []
53
+
54
+ post_install_message:
55
+ rdoc_options:
56
+ - --line-numbers
57
+ - --inline-source
58
+ - --title
59
+ - Timestamper
60
+ - --main
61
+ - README.rdoc
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ segments:
69
+ - 0
70
+ version: "0"
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ segments:
76
+ - 1
77
+ - 2
78
+ version: "1.2"
79
+ requirements: []
80
+
81
+ rubyforge_project: timestamper
82
+ rubygems_version: 1.3.6
83
+ signing_key:
84
+ specification_version: 3
85
+ summary: This gem sets Last-Modified in http response header with timestamp extracted from ActiveResource.
86
+ test_files: []
87
+