ohm-contrib 2.0.0.alpha5 → 2.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gems +4 -0
- data/.gitignore +29 -0
- data/CHANGELOG.md +45 -0
- data/README.markdown +3 -23
- data/lib/ohm/contrib.rb +8 -8
- data/lib/ohm/datatypes.rb +11 -20
- data/lib/ohm/locking.rb +7 -9
- data/lib/ohm/slug.rb +3 -2
- data/lib/ohm/softdelete.rb +12 -15
- data/lib/ohm/timestamps.rb +1 -1
- data/lib/ohm/versioned.rb +1 -1
- data/makefile +4 -0
- data/ohm-contrib.gemspec +5 -15
- data/test/callbacks.rb +119 -0
- data/test/contrib.rb +13 -0
- data/test/datatypes.rb +151 -0
- data/test/helper.rb +1 -16
- data/test/locking.rb +10 -0
- data/test/scope.rb +10 -12
- data/test/slug.rb +13 -7
- data/test/{soft_delete.rb → softdelete.rb} +15 -20
- data/test/timestamp.rb +19 -10
- data/test/versioned.rb +6 -5
- metadata +34 -13
- data/test/instance_callbacks.rb +0 -43
- data/test/plugin.rb +0 -299
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fe7d66dde39d334e746974535e9c58409ea01946
|
4
|
+
data.tar.gz: 6f1bd0fdb34ea731c84c927c0befdea5e93009ec
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f710be3a098d1a740b4849d1b2377afffd9709114ab624c4c70d5bfb8536b2cfa7a0418239da997c0c74d20aff80a4f86d660138b1f2b943f908760302e229f5
|
7
|
+
data.tar.gz: 774494ccaf92fa8a29256be6f114e3cd683f560eb258fc1e2393e8e1005afac6197adf7d5f2a0e609f4f1f3360b8d5210ba93453341507c28d61408b9a333447
|
data/.gems
ADDED
data/.gitignore
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
## MAC OS
|
2
|
+
.DS_Store
|
3
|
+
|
4
|
+
## TEXTMATE
|
5
|
+
*.tmproj
|
6
|
+
tmtags
|
7
|
+
|
8
|
+
## EMACS
|
9
|
+
*~
|
10
|
+
\#*
|
11
|
+
.\#*
|
12
|
+
|
13
|
+
## VIM
|
14
|
+
*.swp
|
15
|
+
|
16
|
+
## PROJECT::GENERAL
|
17
|
+
coverage
|
18
|
+
rdoc
|
19
|
+
pkg
|
20
|
+
|
21
|
+
## PROJECT::SPECIFIC
|
22
|
+
/.rvmrc
|
23
|
+
/.yardoc
|
24
|
+
/doc
|
25
|
+
/tests
|
26
|
+
|
27
|
+
## rbenv
|
28
|
+
.rbenv-gemsets
|
29
|
+
.rbenv-version
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
* Support for Ohm 1.3.x has been removed. It only supports Ohm 2.x.
|
2
|
+
|
3
|
+
1.2
|
4
|
+
===
|
5
|
+
|
6
|
+
* Support for <= 1.1 versions has been removed.Ohm-contrib v1.2 should be used
|
7
|
+
with Ohm 1.2 and above only, due to the change in the way the `Ohm::Set` and
|
8
|
+
`Ohm::MultiSet` are defined. The way to extend #initialize on both has changed.
|
9
|
+
|
10
|
+
1.1.1
|
11
|
+
=====
|
12
|
+
|
13
|
+
* Add Symbol and Set datatypes.
|
14
|
+
|
15
|
+
Example:
|
16
|
+
|
17
|
+
class Foo < Ohm::Model
|
18
|
+
include Ohm::DataTypes
|
19
|
+
|
20
|
+
attribute :state, Type::Symbol
|
21
|
+
attribute :bar_ids, Type::Set
|
22
|
+
end
|
23
|
+
|
24
|
+
1.0.0
|
25
|
+
=====
|
26
|
+
|
27
|
+
* `Ohm::Typecast` has been removed in favor of `Ohm::DataTypes`.
|
28
|
+
|
29
|
+
* `Ohm::Timestamping` has been renamed to `Ohm::Timestamps`.
|
30
|
+
|
31
|
+
* `Ohm::Timestamps` now store times as a UNIX Timestamp.
|
32
|
+
|
33
|
+
* `All Ohm validation related plugins have been removed.
|
34
|
+
See [scrivener][scrivener] instead.
|
35
|
+
|
36
|
+
* `Ohm::Boundaries` has been removed.
|
37
|
+
|
38
|
+
* `Ohm::Contrib` no longer uses `autoload`. You can either `require 'ohm/contrib'`,
|
39
|
+
which requires everything, or you can `require 'ohm/datatypes'` for example
|
40
|
+
if you want to cherry pick your requires.
|
41
|
+
|
42
|
+
* `Ohm::Callbacks` no longer provides macro style callbacks, i.e.
|
43
|
+
`after :create, :do_something`. Use instance callbacks instead.
|
44
|
+
|
45
|
+
[scrivener]: http://github.com/soveran/scrivener
|
data/README.markdown
CHANGED
@@ -133,7 +133,7 @@ product.meta.kind_of?(Hash)
|
|
133
133
|
product.meta == { resolution: '1280x768', battery: '8 hours' }
|
134
134
|
# => true
|
135
135
|
|
136
|
-
product.
|
136
|
+
product.sizes.kind_of?(Array)
|
137
137
|
# => true
|
138
138
|
|
139
139
|
product.sizes == ['XS S M L XL']
|
@@ -159,7 +159,8 @@ post.to_param == "1-using-ohm-contrib-1.0"
|
|
159
159
|
```
|
160
160
|
|
161
161
|
By default, `Ohm::Slug` tries to load iconv in order to transliterate
|
162
|
-
non-ascii characters.
|
162
|
+
non-ascii characters. For ruby 2 or later, you will need to `gem install iconv`
|
163
|
+
to get transliteration.
|
163
164
|
|
164
165
|
```ruby
|
165
166
|
post = Post.create(:title => "Décor")
|
@@ -193,24 +194,3 @@ rescue Ohm::VersionConflict => ex
|
|
193
194
|
# => true
|
194
195
|
end
|
195
196
|
```
|
196
|
-
|
197
|
-
<a name="upgrade" id="upgrade"></a>
|
198
|
-
|
199
|
-
## Important Upgrade notes from 0.1.x
|
200
|
-
|
201
|
-
The following lists the major changes:
|
202
|
-
|
203
|
-
1. `Ohm::Typecast` has been removed in favor of `Ohm::DataTypes`.
|
204
|
-
2. `Ohm::Timestamping` has been renamed to `Ohm::Timestamps`.
|
205
|
-
3. `Ohm::Timestamps` now store times as a UNIX Timestamp.
|
206
|
-
4. `All Ohm validation related plugins have been removed.
|
207
|
-
See [scrivener][scrivener] instead.
|
208
|
-
5. `Ohm::Boundaries` has been removed.
|
209
|
-
6. Ohm::Contrib no longer uses `autoload`. You can either
|
210
|
-
`require 'ohm/contrib'`, which requires everything, or you
|
211
|
-
can `require ohm/datatypes` for example if you want to cherry
|
212
|
-
pick your requires.
|
213
|
-
7. `Ohm::Callbacks` no longer provides macro style callbacks, i.e.
|
214
|
-
`after :create, :do_something`. Use instance callbacks instead.
|
215
|
-
|
216
|
-
[scrivener]: http://github.com/soveran/scrivener
|
data/lib/ohm/contrib.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
1
|
+
require_relative "callbacks"
|
2
|
+
require_relative "datatypes"
|
3
|
+
require_relative "locking"
|
4
|
+
require_relative "scope"
|
5
|
+
require_relative "slug"
|
6
|
+
require_relative "softdelete"
|
7
|
+
require_relative "timestamps"
|
8
|
+
require_relative "versioned"
|
9
9
|
|
10
10
|
module Ohm
|
11
11
|
module Contrib
|
data/lib/ohm/datatypes.rb
CHANGED
@@ -7,26 +7,17 @@ require "set"
|
|
7
7
|
module Ohm
|
8
8
|
module DataTypes
|
9
9
|
module Type
|
10
|
-
Integer =
|
11
|
-
Decimal =
|
12
|
-
Float =
|
13
|
-
Symbol =
|
14
|
-
Boolean =
|
15
|
-
Time =
|
16
|
-
Date =
|
17
|
-
Timestamp =
|
18
|
-
Hash =
|
19
|
-
Array =
|
20
|
-
Set =
|
21
|
-
end
|
22
|
-
|
23
|
-
def self.bool(val)
|
24
|
-
case val
|
25
|
-
when "false", "0" then false
|
26
|
-
when "true", "1" then true
|
27
|
-
else
|
28
|
-
!! val
|
29
|
-
end
|
10
|
+
Integer = ->(x) { x.to_i }
|
11
|
+
Decimal = ->(x) { BigDecimal(x.to_s) }
|
12
|
+
Float = ->(x) { x.to_f }
|
13
|
+
Symbol = ->(x) { x && x.to_sym }
|
14
|
+
Boolean = ->(x) { !!x }
|
15
|
+
Time = ->(t) { t && (t.kind_of?(::Time) ? t : ::Time.parse(t)) }
|
16
|
+
Date = ->(d) { d && (d.kind_of?(::Date) ? d : ::Date.parse(d)) }
|
17
|
+
Timestamp = ->(t) { t && UnixTime.at(t.to_i) }
|
18
|
+
Hash = ->(h) { h && SerializedHash[h.kind_of?(::Hash) ? h : JSON(h)] }
|
19
|
+
Array = ->(a) { a && SerializedArray.new(a.kind_of?(::Array) ? a : JSON(a)) }
|
20
|
+
Set = ->(s) { s && SerializedSet.new(s.kind_of?(::Set) ? s : JSON(s)) }
|
30
21
|
end
|
31
22
|
|
32
23
|
class UnixTime < Time
|
data/lib/ohm/locking.rb
CHANGED
@@ -8,9 +8,7 @@ module Ohm
|
|
8
8
|
# Lock the object before executing the block, and release it once the block
|
9
9
|
# is done.
|
10
10
|
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
# post = Order.create(:customer => Customer.create)
|
11
|
+
# post = Order.create(customer: Customer.create)
|
14
12
|
# post.mutex(0.01) do
|
15
13
|
# # this block is in a mutex!
|
16
14
|
# end
|
@@ -29,11 +27,11 @@ module Ohm
|
|
29
27
|
#
|
30
28
|
# @see Model#mutex
|
31
29
|
def lock!(wait = 0.1)
|
32
|
-
until key[:_lock]
|
33
|
-
next unless lock = key[:_lock]
|
30
|
+
until redis.call("SETNX", key[:_lock], lock_timeout)
|
31
|
+
next unless lock = redis.call("HGET", key[:_lock])
|
34
32
|
sleep(wait) and next unless lock_expired?(lock)
|
35
33
|
|
36
|
-
break unless lock = key[:_lock]
|
34
|
+
break unless lock = redis.call("GETSET", key[:_lock], lock_timeout)
|
37
35
|
break if lock_expired?(lock)
|
38
36
|
end
|
39
37
|
end
|
@@ -41,15 +39,15 @@ module Ohm
|
|
41
39
|
# Release the lock.
|
42
40
|
# @see Model#mutex
|
43
41
|
def unlock!
|
44
|
-
key[:_lock]
|
42
|
+
redis.call("DEL", key[:_lock])
|
45
43
|
end
|
46
44
|
|
47
45
|
def lock_timeout
|
48
46
|
Time.now.to_f + 1
|
49
47
|
end
|
50
48
|
|
51
|
-
def lock_expired?
|
49
|
+
def lock_expired?(lock)
|
52
50
|
lock.to_f < Time.now.to_f
|
53
51
|
end
|
54
52
|
end
|
55
|
-
end
|
53
|
+
end
|
data/lib/ohm/slug.rb
CHANGED
@@ -11,12 +11,13 @@ module Ohm
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def slug(str = to_s)
|
14
|
-
ret = transcode(str)
|
14
|
+
ret = transcode(str.dup)
|
15
15
|
ret.gsub!("'", "")
|
16
16
|
ret.gsub!(/[^0-9A-Za-z]/u, " ")
|
17
17
|
ret.strip!
|
18
18
|
ret.gsub!(/\s+/, "-")
|
19
|
-
ret.downcase
|
19
|
+
ret.downcase!
|
20
|
+
return ret
|
20
21
|
end
|
21
22
|
module_function :slug
|
22
23
|
|
data/lib/ohm/softdelete.rb
CHANGED
@@ -1,16 +1,14 @@
|
|
1
1
|
module Ohm
|
2
|
-
# Provides support for soft deletion
|
3
|
-
#
|
4
|
-
# @example
|
2
|
+
# Provides support for soft deletion.
|
5
3
|
#
|
6
4
|
# class Post < Ohm::Model
|
7
|
-
#
|
5
|
+
# include Ohm::SoftDelete
|
8
6
|
#
|
9
7
|
# attribute :title
|
10
8
|
# index :title
|
11
9
|
# end
|
12
10
|
#
|
13
|
-
# post = Post.create(:
|
11
|
+
# post = Post.create(title: 'Title')
|
14
12
|
#
|
15
13
|
# post.deleted?
|
16
14
|
# # => false
|
@@ -23,7 +21,7 @@ module Ohm
|
|
23
21
|
# Post.all.empty?
|
24
22
|
# # => true
|
25
23
|
#
|
26
|
-
# Post.find(:
|
24
|
+
# Post.find(title: 'Title').include?(post)
|
27
25
|
# # => true
|
28
26
|
#
|
29
27
|
# Post.exists?(post.id)
|
@@ -33,11 +31,10 @@ module Ohm
|
|
33
31
|
#
|
34
32
|
# post.deleted?
|
35
33
|
# # => true
|
34
|
+
#
|
36
35
|
module SoftDelete
|
37
|
-
DELETED_FLAG = "1"
|
38
|
-
|
39
36
|
def self.included(model)
|
40
|
-
model.attribute :deleted
|
37
|
+
model.attribute :deleted, ->(x) { !!x }
|
41
38
|
|
42
39
|
model.extend ClassMethods
|
43
40
|
end
|
@@ -46,13 +43,13 @@ module Ohm
|
|
46
43
|
redis.queue("MULTI")
|
47
44
|
redis.queue("SREM", model.all.key, id)
|
48
45
|
redis.queue("SADD", model.deleted.key, id)
|
49
|
-
redis.queue("HSET", key, :deleted,
|
46
|
+
redis.queue("HSET", key, :deleted, true)
|
50
47
|
redis.queue("EXEC")
|
51
48
|
redis.commit
|
52
49
|
|
53
|
-
self.deleted =
|
50
|
+
self.deleted = true
|
54
51
|
|
55
|
-
|
52
|
+
self
|
56
53
|
end
|
57
54
|
|
58
55
|
def restore
|
@@ -65,11 +62,11 @@ module Ohm
|
|
65
62
|
|
66
63
|
self.deleted = nil
|
67
64
|
|
68
|
-
|
65
|
+
self
|
69
66
|
end
|
70
67
|
|
71
68
|
def deleted?
|
72
|
-
deleted
|
69
|
+
deleted
|
73
70
|
end
|
74
71
|
|
75
72
|
module ClassMethods
|
@@ -78,7 +75,7 @@ module Ohm
|
|
78
75
|
end
|
79
76
|
|
80
77
|
def exists?(id)
|
81
|
-
super ||
|
78
|
+
super || deleted.exists?(id)
|
82
79
|
end
|
83
80
|
end
|
84
81
|
end
|
data/lib/ohm/timestamps.rb
CHANGED
data/lib/ohm/versioned.rb
CHANGED
data/makefile
ADDED
data/ohm-contrib.gemspec
CHANGED
@@ -1,28 +1,18 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "ohm-contrib"
|
3
|
-
s.version = "2.0.0.
|
3
|
+
s.version = "2.0.0.rc1"
|
4
4
|
s.summary = %{A collection of decoupled drop-in modules for Ohm.}
|
5
5
|
s.description = %{Includes a couple of core functions such as callbacks, timestamping, typecasting and lots of generic validation routines.}
|
6
6
|
s.author = "Cyril David"
|
7
7
|
s.email = "cyx@cyx.is"
|
8
8
|
s.homepage = "http://github.com/cyx/ohm-contrib"
|
9
|
+
s.license = "MIT"
|
9
10
|
|
10
|
-
s.
|
11
|
+
s.files = `git ls-files`.split("\n")
|
11
12
|
|
12
|
-
s.
|
13
|
-
"LICENSE",
|
14
|
-
"README.markdown",
|
15
|
-
"rakefile",
|
16
|
-
"lib/**/*.rb",
|
17
|
-
"*.gemspec",
|
18
|
-
"test/*.*",
|
19
|
-
]
|
20
|
-
|
21
|
-
s.require_paths = ["lib"]
|
22
|
-
s.rubyforge_project = "ohm-contrib"
|
23
|
-
|
24
|
-
s.add_dependency "ohm", "2.0.0.alpha5"
|
13
|
+
s.add_dependency "ohm", "~> 2.0.0.rc1"
|
25
14
|
|
26
15
|
s.add_development_dependency "cutest"
|
16
|
+
s.add_development_dependency "iconv"
|
27
17
|
s.add_development_dependency "override"
|
28
18
|
end
|
data/test/callbacks.rb
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
require_relative "helper"
|
2
|
+
require_relative "../lib/ohm/callbacks"
|
3
|
+
|
4
|
+
class Post < Ohm::Model
|
5
|
+
include Ohm::Callbacks
|
6
|
+
|
7
|
+
attribute :body
|
8
|
+
|
9
|
+
def did?(action)
|
10
|
+
!!instance_variable_get("@#{ action }")
|
11
|
+
end
|
12
|
+
|
13
|
+
def count(action)
|
14
|
+
instance_variable_get("@#{ action }")
|
15
|
+
end
|
16
|
+
|
17
|
+
protected
|
18
|
+
|
19
|
+
def before_create() incr(:do_before_create) end
|
20
|
+
def after_create() incr(:do_after_create) end
|
21
|
+
def before_save() incr(:do_before_save) end
|
22
|
+
def after_save() incr(:do_after_save) end
|
23
|
+
def before_update() incr(:do_before_update) end
|
24
|
+
def after_update() incr(:do_after_update) end
|
25
|
+
def before_delete() incr(:do_before_delete) end
|
26
|
+
def after_delete() incr(:do_after_delete) end
|
27
|
+
|
28
|
+
def incr(action)
|
29
|
+
val = instance_variable_get("@#{ action }")
|
30
|
+
val ||= 0
|
31
|
+
val += 1
|
32
|
+
|
33
|
+
instance_variable_set("@#{ action }", val)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
test "create invokes all callbacks (except update)" do
|
38
|
+
post = Post.create(body: "The Body")
|
39
|
+
|
40
|
+
assert post.did?(:do_before_create)
|
41
|
+
assert post.did?(:do_after_create)
|
42
|
+
assert post.did?(:do_before_save)
|
43
|
+
assert post.did?(:do_after_save)
|
44
|
+
assert !post.did?(:do_before_update)
|
45
|
+
assert !post.did?(:do_after_update)
|
46
|
+
end
|
47
|
+
|
48
|
+
test "create only invokes save / create once" do
|
49
|
+
post = Post.create(body: "The Body")
|
50
|
+
|
51
|
+
assert_equal 1, post.count(:do_before_create)
|
52
|
+
assert_equal 1, post.count(:do_after_create)
|
53
|
+
assert_equal 1, post.count(:do_before_save)
|
54
|
+
assert_equal 1, post.count(:do_after_save)
|
55
|
+
end
|
56
|
+
|
57
|
+
test "ensure create / save callbacks are only called once" do
|
58
|
+
post = Post.new(body: "The Body")
|
59
|
+
post.save
|
60
|
+
|
61
|
+
assert_equal 1, post.count(:do_before_create)
|
62
|
+
assert_equal 1, post.count(:do_after_create)
|
63
|
+
assert_equal 1, post.count(:do_before_save)
|
64
|
+
assert_equal 1, post.count(:do_after_save)
|
65
|
+
end
|
66
|
+
|
67
|
+
test "save of existing record executes save and update callbacks" do
|
68
|
+
post = Post.create(body: "The Body")
|
69
|
+
post = Post[post.id]
|
70
|
+
post.save
|
71
|
+
|
72
|
+
assert ! post.did?(:do_before_create)
|
73
|
+
assert ! post.did?(:do_after_create)
|
74
|
+
|
75
|
+
assert post.did?(:do_before_save)
|
76
|
+
assert post.did?(:do_after_save)
|
77
|
+
assert post.did?(:do_before_update)
|
78
|
+
assert post.did?(:do_after_update)
|
79
|
+
|
80
|
+
assert_equal 1, post.count(:do_before_save)
|
81
|
+
assert_equal 1, post.count(:do_after_save)
|
82
|
+
assert_equal 1, post.count(:do_before_update)
|
83
|
+
assert_equal 1, post.count(:do_after_update)
|
84
|
+
end
|
85
|
+
|
86
|
+
test "save of existing record (using #update)" do
|
87
|
+
post = Post.create(body: "The Body")
|
88
|
+
post = Post[post.id]
|
89
|
+
post.update(body: "New Body")
|
90
|
+
|
91
|
+
assert ! post.did?(:do_before_create)
|
92
|
+
assert ! post.did?(:do_after_create)
|
93
|
+
|
94
|
+
assert post.did?(:do_before_save)
|
95
|
+
assert post.did?(:do_after_save)
|
96
|
+
assert post.did?(:do_before_update)
|
97
|
+
assert post.did?(:do_after_update)
|
98
|
+
|
99
|
+
assert_equal 1, post.count(:do_before_save)
|
100
|
+
assert_equal 1, post.count(:do_after_save)
|
101
|
+
assert_equal 1, post.count(:do_before_update)
|
102
|
+
assert_equal 1, post.count(:do_after_update)
|
103
|
+
end
|
104
|
+
|
105
|
+
test "on delete" do
|
106
|
+
post = Post.create(body: "The Body")
|
107
|
+
post = Post[post.id]
|
108
|
+
post.delete
|
109
|
+
|
110
|
+
assert_equal 1, post.count(:do_before_delete)
|
111
|
+
assert_equal 1, post.count(:do_after_delete)
|
112
|
+
|
113
|
+
assert ! post.did?(:do_before_create)
|
114
|
+
assert ! post.did?(:do_after_create)
|
115
|
+
assert ! post.did?(:do_before_save)
|
116
|
+
assert ! post.did?(:do_after_save)
|
117
|
+
assert ! post.did?(:do_before_update)
|
118
|
+
assert ! post.did?(:do_after_update)
|
119
|
+
end
|