ixtlan-optimistic 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Kristian Meier
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,38 @@
1
+ # Ixtlan Optimistic [![Build Status](https://secure.travis-ci.org/mkristian/ixtlan-optimistic.png)](http://travis-ci.org/mkristian/ixtlan-optimistic) #
2
+
3
+ it adds optimistic persistence support to DataMapper and ActveRecord usingg the updated_at property/attribute which is automatically updated on any change of the model (for datamapper you need dm-timestamps for that). to load a model use `optimistic_get`/`optimistic_get!`/`optimistic_find` respectively where the first argument is the last `updated_at` value which the client has. if the client data is uptodate then the `optimistic_XYZ` method will return the database entity otherwise raise an exception or return nil respectively.
4
+
5
+ ## rails setup ##
6
+
7
+ automagic via included railtie. just add
8
+
9
+ `gem 'ixtlan-optimistic'
10
+
11
+ to your Gemfile.
12
+
13
+ ## datamapper ##
14
+
15
+ just include `Ixtlan::Optimistic::DataMapper` to your model:
16
+
17
+ class User
18
+ include DataMapper::Resource
19
+ include Ixtlan::Optimistic::DataMapper
20
+
21
+ property :id, Serial
22
+ property :name, String
23
+
24
+ timestamps :at
25
+ end
26
+
27
+ you need timestamps to get to work !
28
+
29
+ ## activerecord ##
30
+
31
+ just add it with
32
+
33
+ ::ActiveRecord::Base.send(:include,
34
+ Ixtlan::Optimistic::ActiveRecord)
35
+
36
+ # meta-fu #
37
+
38
+ bug-reports, feature request and pull request are most welcome.
@@ -0,0 +1,3 @@
1
+ if defined?(Rails)
2
+ require 'ixtlan/optimistic/railtie'
3
+ end
@@ -0,0 +1,30 @@
1
+ require 'ixtlan/optimistic/object_stale_exception'
2
+ module Ixtlan
3
+ module Optimistic
4
+ module ActiveRecord
5
+
6
+ def self.included(base)
7
+ base.class_eval do
8
+
9
+ def self.optimistic_find(updated_at, *args)
10
+ if updated_at
11
+ dummy = self.new
12
+ dummy.updated_at = updated_at
13
+ updated_at_date = dummy.updated_at
14
+ # try different ways to use the date
15
+ # TODO maybe there is a nicer way ??
16
+ # TODO make it work with different PKs
17
+ result = first(:conditions => ["id = ? and updated_at <= ? and updated_at >= ?", args[0], updated_at_date + 0.0005, updated_at_date - 0.0005])
18
+ p result
19
+ raise ObjectStaleException.new "#{self.class} with ID=#{args[0]} is stale" unless result
20
+ result
21
+ else
22
+ raise ObjectStaleException.new "no 'updated_at' given. could not dind #{self.class} with ID=#{args[0]}."
23
+ end
24
+ end
25
+
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,32 @@
1
+ require 'ixtlan/optimistic/object_stale_exception'
2
+ module Ixtlan
3
+ module Optimistic
4
+ module DataMapper
5
+
6
+ def self.included(base)
7
+ base.class_eval do
8
+
9
+ def self.optimistic_get(updated_at, *args)
10
+ if updated_at
11
+ updated_at_date = new(:updated_at => updated_at).updated_at
12
+ # TODO make it work with different PKs
13
+ first(:id => args[0], :updated_at.gte => updated_at_date - 0.0005, :updated_at.lte => updated_at_date + 0.0005)
14
+ end
15
+ end
16
+
17
+ def self.optimistic_get!(updated_at, *args)
18
+ if updated_at
19
+ result = self.optimistic_get(updated_at, *args)
20
+ raise ObjectStaleException.new "#{self.class} with ID=#{args[0]} is stale" unless result
21
+ result
22
+ else
23
+ raise ObjectStaleException.new "no 'updated_at' given. could not dind #{self.class} with ID=#{args[0]}."
24
+ end
25
+ end
26
+ end
27
+
28
+ end
29
+
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,6 @@
1
+ module Ixtlan
2
+ module Optimistic
3
+ class ObjectStaleException < StandardError
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,21 @@
1
+ require 'ixtlan/optimistic/active_record'
2
+ require 'ixtlan/optimistic/data_mapper'
3
+ module Ixtlan
4
+ module Optimistic
5
+ class Railtie < Rails::Railtie
6
+
7
+ config.after_initialize do
8
+ if defined? ::DataMapper
9
+
10
+ ::DataMapper::Model.append_inclusions(Ixtlan::Optimistic::DataMapper)
11
+
12
+ elsif defined? ::ActiveRecord
13
+
14
+ ::ActiveRecord::Base.send(:include,
15
+ Ixtlan::Optimistic::ActiveRecord)
16
+
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,38 @@
1
+ require 'dm-core'
2
+ require 'dm-timestamps'
3
+ require 'dm-migrations'
4
+ require 'dm-sqlite-adapter'
5
+ require 'ixtlan/optimistic/data_mapper'
6
+
7
+ DataMapper.setup(:default, 'sqlite::memory:')
8
+
9
+ class A
10
+ include DataMapper::Resource
11
+ include Ixtlan::Optimistic::DataMapper
12
+
13
+ property :id, Serial
14
+ property :name, String
15
+
16
+ timestamps :at
17
+ end
18
+
19
+ DataMapper.finalize
20
+ DataMapper.auto_migrate!
21
+
22
+ describe Ixtlan::Optimistic::DataMapper do
23
+
24
+ subject { A.create :name => 'huffalump' }
25
+
26
+ it 'should load' do
27
+ A.optimistic_get!(subject.updated_at.to_s, subject.id).must_equal subject
28
+ end
29
+
30
+ it 'should fail with nil' do
31
+ A.optimistic_get((subject.updated_at - 1000).to_s, subject.id).must_be_nil
32
+ end
33
+
34
+ it 'should fail with exception' do
35
+ lambda { A.optimistic_get!((subject.updated_at - 1000).to_s, subject.id) }.must_raise Ixtlan::Optimistic::ObjectStaleException
36
+ end
37
+
38
+ end
@@ -0,0 +1,74 @@
1
+ require 'controller'
2
+
3
+ shared_examples 'a X-Headers' do
4
+
5
+ it 'should be able to switch off' do
6
+ subject.send method, :inline => "asd", :x_frame_headers => :off, :x_content_type_headers => :off, :x_xss_protection_headers => :off
7
+ subject.response.headers.should == {}
8
+ end
9
+
10
+ end
11
+
12
+ class MyController < Controller
13
+ x_frame_headers :sameorigin
14
+ x_content_type_headers :off
15
+ x_xss_protection_headers :disabled
16
+ end
17
+
18
+ [:render, :send_file, :send_data].each do |method|
19
+ describe "x-headers using controller method #{method}" do
20
+ context "with simple controller" do
21
+ before do
22
+ Rails.configuration.x_frame_headers = nil
23
+ Rails.configuration.x_content_type_headers = nil
24
+ Rails.configuration.x_xss_protection_headers = nil
25
+ end
26
+ subject { Controller.new }
27
+
28
+ it 'should use default' do
29
+ subject.send method, :inline => "asd"
30
+ subject.response.headers.should == {"X-Frame-Options"=>"DENY", "X-Content-Type-Options"=>"nosniff", "X-XSS-Protection"=>"1; mode=block"}
31
+ end
32
+
33
+ it_behaves_like "a X-Headers" do
34
+ let(:method) { method }
35
+ end
36
+ end
37
+
38
+ context "with controller with header configuration" do
39
+ before do
40
+ Rails.configuration.x_frame_headers = nil
41
+ Rails.configuration.x_content_type_headers = nil
42
+ Rails.configuration.x_xss_protection_headers = nil
43
+ end
44
+ subject { MyController.new }
45
+
46
+ it 'should use configuration' do
47
+ subject.send method, :inline => "asd"
48
+ subject.response.headers.should == {"X-Frame-Options"=>"SAMEORIGIN", "X-XSS-Protection"=>"0"}
49
+ end
50
+
51
+ it_behaves_like "a X-Headers" do
52
+ let(:method) { method }
53
+ end
54
+ end
55
+
56
+ context "with simple controller with rails configuration" do
57
+ before do
58
+ Rails.configuration.x_frame_headers = :sameorigin
59
+ Rails.configuration.x_content_type_headers = :off
60
+ Rails.configuration.x_xss_protection_headers = :disabled
61
+ end
62
+ subject { Controller.new }
63
+
64
+ it 'should use configuration' do
65
+ subject.send method, :inline => "asd"
66
+ subject.response.headers.should == {"X-Frame-Options"=>"SAMEORIGIN", "X-XSS-Protection"=>"0"}
67
+ end
68
+
69
+ it_behaves_like "a X-Headers" do
70
+ let(:method) { method }
71
+ end
72
+ end
73
+ end
74
+ end
metadata ADDED
@@ -0,0 +1,155 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ixtlan-optimistic
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - mkristian
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-07-07 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: minitest
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - "="
27
+ - !ruby/object:Gem::Version
28
+ hash: 15
29
+ segments:
30
+ - 3
31
+ - 2
32
+ - 0
33
+ version: 3.2.0
34
+ type: :development
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: dm-timestamps
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - "="
43
+ - !ruby/object:Gem::Version
44
+ hash: 31
45
+ segments:
46
+ - 1
47
+ - 2
48
+ - 0
49
+ version: 1.2.0
50
+ type: :development
51
+ version_requirements: *id002
52
+ - !ruby/object:Gem::Dependency
53
+ name: dm-migrations
54
+ prerelease: false
55
+ requirement: &id003 !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - "="
59
+ - !ruby/object:Gem::Version
60
+ hash: 31
61
+ segments:
62
+ - 1
63
+ - 2
64
+ - 0
65
+ version: 1.2.0
66
+ type: :development
67
+ version_requirements: *id003
68
+ - !ruby/object:Gem::Dependency
69
+ name: dm-sqlite-adapter
70
+ prerelease: false
71
+ requirement: &id004 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - "="
75
+ - !ruby/object:Gem::Version
76
+ hash: 31
77
+ segments:
78
+ - 1
79
+ - 2
80
+ - 0
81
+ version: 1.2.0
82
+ type: :development
83
+ version_requirements: *id004
84
+ - !ruby/object:Gem::Dependency
85
+ name: rake
86
+ prerelease: false
87
+ requirement: &id005 !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - "="
91
+ - !ruby/object:Gem::Version
92
+ hash: 11
93
+ segments:
94
+ - 0
95
+ - 9
96
+ - 2
97
+ - 2
98
+ version: 0.9.2.2
99
+ type: :development
100
+ version_requirements: *id005
101
+ description: optimistic find/get on model via updated_at timestamp for datamapper and activerecord
102
+ email:
103
+ - m.kristian@web.de
104
+ executables: []
105
+
106
+ extensions: []
107
+
108
+ extra_rdoc_files: []
109
+
110
+ files:
111
+ - MIT-LICENSE
112
+ - README.md
113
+ - lib/ixtlan-optimistic.rb
114
+ - lib/ixtlan/optimistic/active_record.rb
115
+ - lib/ixtlan/optimistic/data_mapper.rb
116
+ - lib/ixtlan/optimistic/railtie.rb
117
+ - lib/ixtlan/optimistic/object_stale_exception.rb
118
+ - spec/datamapper_spec.rb~
119
+ - spec/datamapper_spec.rb
120
+ homepage: http://github.com/mkristian/ixtlan-optimistic
121
+ licenses:
122
+ - MIT-LICENSE
123
+ post_install_message:
124
+ rdoc_options:
125
+ - --main
126
+ - README.md
127
+ require_paths:
128
+ - lib
129
+ required_ruby_version: !ruby/object:Gem::Requirement
130
+ none: false
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ hash: 3
135
+ segments:
136
+ - 0
137
+ version: "0"
138
+ required_rubygems_version: !ruby/object:Gem::Requirement
139
+ none: false
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ hash: 3
144
+ segments:
145
+ - 0
146
+ version: "0"
147
+ requirements: []
148
+
149
+ rubyforge_project:
150
+ rubygems_version: 1.8.21
151
+ signing_key:
152
+ specification_version: 3
153
+ summary: optimistic find/get on model via updated_at timestamp for datamapper and activerecord
154
+ test_files:
155
+ - spec/datamapper_spec.rb