ohm-contrib 2.0.0.alpha5 → 2.0.0.rc1

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