ixtlan-optimistic 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,6 +1,12 @@
1
- # Ixtlan Optimistic [![Build Status](https://secure.travis-ci.org/mkristian/ixtlan-optimistic.png)](http://travis-ci.org/mkristian/ixtlan-optimistic) #
1
+ # Ixtlan Optimistic #
2
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.
3
+ * [![Build Status](https://secure.travis-ci.org/mkristian/ixtlan-optimistic.png)](http://travis-ci.org/mkristian/ixtlan-optimistic)
4
+ * [![Dependency Status](https://gemnasium.com/mkristian/ixtlan-optimistic.png)](https://gemnasium.com/mkristian/ixtlan-optimistic)
5
+ * [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/mkristian/ixtlan-optimistic)
6
+
7
+
8
+
9
+ it adds optimistic persistence support to DataMapper and ActveRecord using 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
10
 
5
11
  ## rails setup ##
6
12
 
@@ -33,6 +39,16 @@ just add it with
33
39
  ::ActiveRecord::Base.send(:include,
34
40
  Ixtlan::Optimistic::ActiveRecord)
35
41
 
36
- # meta-fu #
42
+ Contributing
43
+ ------------
44
+
45
+ 1. Fork it
46
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
47
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
48
+ 4. Push to the branch (`git push origin my-new-feature`)
49
+ 5. Create new Pull Request
50
+
51
+ meta-fu
52
+ -------
37
53
 
38
- bug-reports, feature request and pull request are most welcome.
54
+ enjoy :)
@@ -1,3 +1,23 @@
1
+ #
2
+ # Copyright (C) 2012 mkristian
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+ # this software and associated documentation files (the "Software"), to deal in
6
+ # the Software without restriction, including without limitation the rights to
7
+ # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8
+ # the Software, and to permit persons to whom the Software is furnished to do so,
9
+ # subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in all
12
+ # copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18
+ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
+ #
1
21
  if defined?(Rails)
2
22
  require 'ixtlan/optimistic/railtie'
3
23
  end
@@ -1,28 +1,39 @@
1
+ #
2
+ # Copyright (C) 2012 mkristian
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+ # this software and associated documentation files (the "Software"), to deal in
6
+ # the Software without restriction, including without limitation the rights to
7
+ # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8
+ # the Software, and to permit persons to whom the Software is furnished to do so,
9
+ # subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in all
12
+ # copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18
+ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
+ #
1
21
  require 'ixtlan/optimistic/object_stale_exception'
22
+ require 'ixtlan/optimistic/stale_check'
2
23
  module Ixtlan
3
24
  module Optimistic
4
25
  module ActiveRecord
5
26
 
6
27
  def self.included(base)
28
+ base.extend StaleCheck
7
29
  base.class_eval do
8
-
9
30
  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]}."
31
+ __check( updated_at )
32
+ result = find( *args )
33
+ if result
34
+ __check_stale( updated_at, result )
23
35
  end
24
36
  end
25
-
26
37
  end
27
38
  end
28
39
  end
@@ -1,32 +1,48 @@
1
+ #
2
+ # Copyright (C) 2012 mkristian
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+ # this software and associated documentation files (the "Software"), to deal in
6
+ # the Software without restriction, including without limitation the rights to
7
+ # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8
+ # the Software, and to permit persons to whom the Software is furnished to do so,
9
+ # subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in all
12
+ # copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18
+ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
+ #
1
21
  require 'ixtlan/optimistic/object_stale_exception'
22
+ require 'ixtlan/optimistic/stale_check'
2
23
  module Ixtlan
3
24
  module Optimistic
4
25
  module DataMapper
5
26
 
6
27
  def self.included(base)
28
+ base.extend StaleCheck
7
29
  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)
30
+
31
+ def self.optimistic_get(updated_at, *args)
32
+ __check( updated_at )
33
+ result = get( *args )
34
+ if result
35
+ __check_stale( updated_at, result )
14
36
  end
15
37
  end
16
-
38
+
17
39
  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
40
+ __check( updated_at )
41
+ result = get!( *args )
42
+ __check_stale( updated_at, result )
25
43
  end
26
44
  end
27
-
28
45
  end
29
-
30
46
  end
31
47
  end
32
48
  end
@@ -1,3 +1,23 @@
1
+ #
2
+ # Copyright (C) 2012 mkristian
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+ # this software and associated documentation files (the "Software"), to deal in
6
+ # the Software without restriction, including without limitation the rights to
7
+ # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8
+ # the Software, and to permit persons to whom the Software is furnished to do so,
9
+ # subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in all
12
+ # copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18
+ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
+ #
1
21
  module Ixtlan
2
22
  module Optimistic
3
23
  class ObjectStaleException < StandardError
@@ -1,3 +1,23 @@
1
+ #
2
+ # Copyright (C) 2012 mkristian
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+ # this software and associated documentation files (the "Software"), to deal in
6
+ # the Software without restriction, including without limitation the rights to
7
+ # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8
+ # the Software, and to permit persons to whom the Software is furnished to do so,
9
+ # subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in all
12
+ # copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18
+ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
+ #
1
21
  require 'ixtlan/optimistic/active_record'
2
22
  require 'ixtlan/optimistic/data_mapper'
3
23
  module Ixtlan
@@ -18,4 +38,4 @@ module Ixtlan
18
38
  end
19
39
  end
20
40
  end
21
- end
41
+ end
@@ -0,0 +1,45 @@
1
+ #
2
+ # Copyright (C) 2012 mkristian
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+ # this software and associated documentation files (the "Software"), to deal in
6
+ # the Software without restriction, including without limitation the rights to
7
+ # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8
+ # the Software, and to permit persons to whom the Software is furnished to do so,
9
+ # subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in all
12
+ # copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18
+ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
+ #
21
+ require 'ixtlan/optimistic/object_stale_exception'
22
+ module Ixtlan
23
+ module Optimistic
24
+ module StaleCheck
25
+
26
+ def __check( updated_at )
27
+ unless updated_at
28
+ raise ObjectStaleException.new "no 'updated_at' given. could not find #{signature(*args)}."
29
+ end
30
+ end
31
+
32
+ def __check_stale( updated_at, result )
33
+ if updated_at.is_a?( String )
34
+ updated_at = DateTime.parse( updated_at.sub(/[.][0-9]+/, '') )
35
+ end
36
+ updated_at = updated_at.new_offset(0)
37
+ if updated_at != result.updated_at && updated_at.strftime("%Y:%m:%d %H:%M:%S") != result.updated_at.new_offset(0).strftime("%Y:%m:%d %H:%M:%S")
38
+
39
+ raise ObjectStaleException.new "#{result.inspect} is stale for updated at #{updated_at}."
40
+ end
41
+ result
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,66 @@
1
+ #
2
+ # Copyright (C) 2012 mkristian
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+ # this software and associated documentation files (the "Software"), to deal in
6
+ # the Software without restriction, including without limitation the rights to
7
+ # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8
+ # the Software, and to permit persons to whom the Software is furnished to do so,
9
+ # subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in all
12
+ # copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18
+ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
+ #
21
+ require 'ixtlan/optimistic/object_stale_exception'
22
+ module Ixtlan
23
+ module Optimistic
24
+ module DataMapper
25
+
26
+ def self.included(base)
27
+ base.class_eval do
28
+ private
29
+
30
+ def self.__check( updated_at )
31
+ unless updated_at
32
+ raise ObjectStaleException.new "no 'updated_at' given. could not find #{signature(*args)}."
33
+ end
34
+ end
35
+
36
+ def self.__check_stale( updated_at, result )
37
+ if updated_at.is_a?( String )
38
+ updated_at = DateTime.parse( updated_at.sub(/[.][0-9]+/, '') )
39
+ end
40
+ if updated_at != result.updated_at && updated_at.strftime("%Y:%m:%d %H:%M:%S") != result.updated_at.strftime("%Y:%m:%d %H:%M:%S")
41
+
42
+ raise ObjectStaleException.new "#{self.class} with key #{result.key} is stale for updated at #{updated_at}."
43
+ end
44
+ result
45
+ end
46
+
47
+ public
48
+
49
+ def self.optimistic_get(updated_at, *args)
50
+ __check( updated_at )
51
+ result = get( *args )
52
+ if result
53
+ __check_stale( updated_at, result )
54
+ end
55
+ end
56
+
57
+ def self.optimistic_get!(updated_at, *args)
58
+ __check( updated_at )
59
+ result = get!( *args )
60
+ __check_stale( updated_at, result )
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -23,16 +23,36 @@ describe Ixtlan::Optimistic::DataMapper do
23
23
 
24
24
  subject { A.create :name => 'huffalump' }
25
25
 
26
- it 'should load' do
27
- A.optimistic_get!(subject.updated_at.to_s, subject.id).must_equal subject
28
- end
26
+ describe "#optimistic_get" do
27
+
28
+ it 'should load' do
29
+ A.optimistic_get(subject.updated_at.to_s, subject.id).must_equal subject
30
+ end
31
+
32
+ it 'should fail with stale exception' do
33
+ lambda { A.optimistic_get((subject.updated_at - 1000).to_s, subject.id) }.must_raise Ixtlan::Optimistic::ObjectStaleException
34
+ end
35
+
36
+ it 'should fail with nil' do
37
+ A.optimistic_get(subject.updated_at.to_s, subject.id + 987).must_be_nil
38
+ end
29
39
 
30
- it 'should fail with nil' do
31
- A.optimistic_get((subject.updated_at - 1000).to_s, subject.id).must_be_nil
32
40
  end
33
41
 
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
42
+ describe "#optimistic_get!" do
43
+
44
+ it 'should load' do
45
+ A.optimistic_get!(subject.updated_at.to_s, subject.id).must_equal subject
46
+ end
47
+
48
+ it 'should fail with not-found exception' do
49
+ lambda { A.optimistic_get!(subject.updated_at.to_s, subject.id + 987) }.must_raise DataMapper::ObjectNotFoundError
50
+ end
51
+
52
+ it 'should fail with stale exception' do
53
+ lambda { A.optimistic_get!((subject.updated_at - 1000).to_s, subject.id) }.must_raise Ixtlan::Optimistic::ObjectStaleException
54
+ end
55
+
36
56
  end
37
57
 
38
58
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ixtlan-optimistic
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 23
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 1
8
+ - 2
9
9
  - 0
10
- version: 0.1.0
10
+ version: 0.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - mkristian
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-07-07 00:00:00 Z
18
+ date: 2012-12-29 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: minitest
@@ -23,14 +23,14 @@ dependencies:
23
23
  requirement: &id001 !ruby/object:Gem::Requirement
24
24
  none: false
25
25
  requirements:
26
- - - "="
26
+ - - ~>
27
27
  - !ruby/object:Gem::Version
28
- hash: 15
28
+ hash: 51
29
29
  segments:
30
+ - 4
30
31
  - 3
31
- - 2
32
32
  - 0
33
- version: 3.2.0
33
+ version: 4.3.0
34
34
  type: :development
35
35
  version_requirements: *id001
36
36
  - !ruby/object:Gem::Dependency
@@ -87,17 +87,31 @@ dependencies:
87
87
  requirement: &id005 !ruby/object:Gem::Requirement
88
88
  none: false
89
89
  requirements:
90
- - - "="
90
+ - - ~>
91
91
  - !ruby/object:Gem::Version
92
- hash: 11
92
+ hash: 75
93
93
  segments:
94
+ - 10
94
95
  - 0
95
- - 9
96
96
  - 2
97
- - 2
98
- version: 0.9.2.2
97
+ version: 10.0.2
99
98
  type: :development
100
99
  version_requirements: *id005
100
+ - !ruby/object:Gem::Dependency
101
+ name: copyright-header
102
+ prerelease: false
103
+ requirement: &id006 !ruby/object:Gem::Requirement
104
+ none: false
105
+ requirements:
106
+ - - ~>
107
+ - !ruby/object:Gem::Version
108
+ hash: 15
109
+ segments:
110
+ - 1
111
+ - 0
112
+ version: "1.0"
113
+ type: :development
114
+ version_requirements: *id006
101
115
  description: optimistic find/get on model via updated_at timestamp for datamapper and activerecord
102
116
  email:
103
117
  - m.kristian@web.de
@@ -112,14 +126,16 @@ files:
112
126
  - README.md
113
127
  - lib/ixtlan-optimistic.rb
114
128
  - lib/ixtlan/optimistic/active_record.rb
129
+ - lib/ixtlan/optimistic/stale_check.rb~
115
130
  - lib/ixtlan/optimistic/data_mapper.rb
131
+ - lib/ixtlan/optimistic/stale_check.rb
116
132
  - lib/ixtlan/optimistic/railtie.rb
117
133
  - lib/ixtlan/optimistic/object_stale_exception.rb
118
134
  - spec/datamapper_spec.rb~
119
135
  - spec/datamapper_spec.rb
120
136
  homepage: http://github.com/mkristian/ixtlan-optimistic
121
137
  licenses:
122
- - MIT-LICENSE
138
+ - MIT
123
139
  post_install_message:
124
140
  rdoc_options:
125
141
  - --main
@@ -147,7 +163,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
147
163
  requirements: []
148
164
 
149
165
  rubyforge_project:
150
- rubygems_version: 1.8.21
166
+ rubygems_version: 1.8.15
151
167
  signing_key:
152
168
  specification_version: 3
153
169
  summary: optimistic find/get on model via updated_at timestamp for datamapper and activerecord