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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b37b722586fa921921b02393434ee62b0df99d9e
4
- data.tar.gz: d6cec02d9a3edeb0255440f06a925ca6724d35bd
3
+ metadata.gz: fe7d66dde39d334e746974535e9c58409ea01946
4
+ data.tar.gz: 6f1bd0fdb34ea731c84c927c0befdea5e93009ec
5
5
  SHA512:
6
- metadata.gz: b716eb058df3142838c8095aff4bb445cb39eab699fe95104f86f2873112b34127dd68e0a0040b0a77d87a70bb2c9b5fd3196bfd51c0d32266818f75893fcf3b
7
- data.tar.gz: 11e0da50b18ad6bf152ddd443e61ad39a83be55fa2f1a1a9b45837f85e5c360519e80e915571b53d95c30c6ef904bbd8a8b4e61df21c1431eb4559c4e3c12d0c
6
+ metadata.gz: f710be3a098d1a740b4849d1b2377afffd9709114ab624c4c70d5bfb8536b2cfa7a0418239da997c0c74d20aff80a4f86d660138b1f2b943f908760302e229f5
7
+ data.tar.gz: 774494ccaf92fa8a29256be6f114e3cd683f560eb258fc1e2393e8e1005afac6197adf7d5f2a0e609f4f1f3360b8d5210ba93453341507c28d61408b9a333447
data/.gems ADDED
@@ -0,0 +1,4 @@
1
+ cutest -v 1.2.1
2
+ iconv -v 1.0.4
3
+ ohm -v 2.0.0.rc1
4
+ override -v 0.0.10
@@ -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
@@ -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
@@ -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.meta.kind_of?(Array)
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
@@ -1,11 +1,11 @@
1
- require File.expand_path("../callbacks", __FILE__)
2
- require File.expand_path("../datatypes", __FILE__)
3
- require File.expand_path("../locking", __FILE__)
4
- require File.expand_path("../scope", __FILE__)
5
- require File.expand_path("../slug", __FILE__)
6
- require File.expand_path("../softdelete", __FILE__)
7
- require File.expand_path("../timestamps", __FILE__)
8
- require File.expand_path("../versioned", __FILE__)
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
@@ -7,26 +7,17 @@ require "set"
7
7
  module Ohm
8
8
  module DataTypes
9
9
  module Type
10
- Integer = lambda { |x| x.to_i }
11
- Decimal = lambda { |x| BigDecimal(x.to_s) }
12
- Float = lambda { |x| x.to_f }
13
- Symbol = lambda { |x| x && x.to_sym }
14
- Boolean = lambda { |x| Ohm::DataTypes.bool(x) }
15
- Time = lambda { |t| t && (t.kind_of?(::Time) ? t : ::Time.parse(t)) }
16
- Date = lambda { |d| d && (d.kind_of?(::Date) ? d : ::Date.parse(d)) }
17
- Timestamp = lambda { |t| t && UnixTime.at(t.to_i) }
18
- Hash = lambda { |h| h && SerializedHash[h.kind_of?(::Hash) ? h : JSON(h)] }
19
- Array = lambda { |a| a && SerializedArray.new(a.kind_of?(::Array) ? a : JSON(a)) }
20
- Set = lambda { |s| s && SerializedSet.new(s.kind_of?(::Set) ? s : JSON(s)) }
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
@@ -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
- # @example
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].setnx(lock_timeout)
33
- next unless lock = key[:_lock].get
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].getset(lock_timeout)
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].del
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? lock
49
+ def lock_expired?(lock)
52
50
  lock.to_f < Time.now.to_f
53
51
  end
54
52
  end
55
- end
53
+ end
@@ -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
 
@@ -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
- # plugin :softdelete
5
+ # include Ohm::SoftDelete
8
6
  #
9
7
  # attribute :title
10
8
  # index :title
11
9
  # end
12
10
  #
13
- # post = Post.create(:title => 'Title')
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(:title => 'Title').include?(post)
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, DELETED_FLAG)
46
+ redis.queue("HSET", key, :deleted, true)
50
47
  redis.queue("EXEC")
51
48
  redis.commit
52
49
 
53
- self.deleted = DELETED_FLAG
50
+ self.deleted = true
54
51
 
55
- return self
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
- return self
65
+ self
69
66
  end
70
67
 
71
68
  def deleted?
72
- deleted == DELETED_FLAG
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 || redis.call("SISMEMBER", key[:deleted], id) == 1
78
+ super || deleted.exists?(id)
82
79
  end
83
80
  end
84
81
  end
@@ -1,4 +1,4 @@
1
- require File.expand_path("../datatypes", __FILE__)
1
+ require_relative "datatypes"
2
2
 
3
3
  module Ohm
4
4
  # Provides created_at / updated_at timestamps.
@@ -1,7 +1,7 @@
1
1
  module Ohm
2
2
  module Versioned
3
3
  def self.included(model)
4
- model.attribute :_version, lambda { |x| x.to_i }
4
+ model.attribute :_version, ->(x) { x.to_i }
5
5
  end
6
6
 
7
7
  def save
@@ -0,0 +1,4 @@
1
+ .PHONY: test
2
+
3
+ test:
4
+ cutest test/*.rb
@@ -1,28 +1,18 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "ohm-contrib"
3
- s.version = "2.0.0.alpha5"
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.specification_version = 2 if s.respond_to? :specification_version=
11
+ s.files = `git ls-files`.split("\n")
11
12
 
12
- s.files = Dir[
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
@@ -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