ixtlan-optimistic 0.1.0

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.
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