familia 0.10.2 → 1.0.0.pre.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.pre-commit-config.yaml +1 -1
  4. data/.rubocop.yml +75 -0
  5. data/.rubocop_todo.yml +63 -0
  6. data/Gemfile +6 -1
  7. data/Gemfile.lock +47 -15
  8. data/README.md +11 -12
  9. data/VERSION.yml +4 -3
  10. data/familia.gemspec +18 -13
  11. data/lib/familia/base.rb +33 -0
  12. data/lib/familia/connection.rb +87 -0
  13. data/lib/familia/core_ext.rb +119 -124
  14. data/lib/familia/errors.rb +33 -0
  15. data/lib/familia/features/api_version.rb +19 -0
  16. data/lib/familia/features/atomic_saves.rb +8 -0
  17. data/lib/familia/features/quantizer.rb +35 -0
  18. data/lib/familia/features/safe_dump.rb +175 -0
  19. data/lib/familia/features.rb +51 -0
  20. data/lib/familia/horreum/class_methods.rb +240 -0
  21. data/lib/familia/horreum/commands.rb +59 -0
  22. data/lib/familia/horreum/relations_management.rb +141 -0
  23. data/lib/familia/horreum/serialization.rb +154 -0
  24. data/lib/familia/horreum/settings.rb +63 -0
  25. data/lib/familia/horreum/utils.rb +43 -0
  26. data/lib/familia/horreum.rb +198 -0
  27. data/lib/familia/logging.rb +249 -0
  28. data/lib/familia/redistype/commands.rb +56 -0
  29. data/lib/familia/redistype/serialization.rb +110 -0
  30. data/lib/familia/redistype.rb +185 -0
  31. data/lib/familia/settings.rb +38 -0
  32. data/lib/familia/types/hashkey.rb +108 -0
  33. data/lib/familia/types/list.rb +155 -0
  34. data/lib/familia/types/sorted_set.rb +234 -0
  35. data/lib/familia/types/string.rb +115 -0
  36. data/lib/familia/types/unsorted_set.rb +123 -0
  37. data/lib/familia/utils.rb +129 -0
  38. data/lib/familia/version.rb +25 -0
  39. data/lib/familia.rb +56 -161
  40. data/lib/redis_middleware.rb +109 -0
  41. data/try/00_familia_try.rb +5 -4
  42. data/try/10_familia_try.rb +21 -17
  43. data/try/20_redis_type_try.rb +67 -0
  44. data/try/{21_redis_object_zset_try.rb → 21_redis_type_zset_try.rb} +2 -2
  45. data/try/{22_redis_object_set_try.rb → 22_redis_type_set_try.rb} +2 -2
  46. data/try/{23_redis_object_list_try.rb → 23_redis_type_list_try.rb} +2 -2
  47. data/try/{24_redis_object_string_try.rb → 24_redis_type_string_try.rb} +6 -6
  48. data/try/{25_redis_object_hash_try.rb → 25_redis_type_hash_try.rb} +3 -3
  49. data/try/26_redis_bool_try.rb +10 -6
  50. data/try/27_redis_horreum_try.rb +40 -0
  51. data/try/30_familia_object_try.rb +21 -20
  52. data/try/35_feature_safedump_try.rb +83 -0
  53. data/try/40_customer_try.rb +140 -0
  54. data/try/41_customer_safedump_try.rb +86 -0
  55. data/try/test_helpers.rb +186 -0
  56. metadata +50 -47
  57. data/lib/familia/helpers.rb +0 -70
  58. data/lib/familia/object.rb +0 -533
  59. data/lib/familia/redisobject.rb +0 -1017
  60. data/lib/familia/test_helpers.rb +0 -40
  61. data/lib/familia/tools.rb +0 -67
  62. data/try/20_redis_object_try.rb +0 -44
@@ -0,0 +1,140 @@
1
+ # Customer Tryouts
2
+ require_relative '../lib/familia'
3
+ require_relative './test_helpers'
4
+
5
+ # Setup
6
+ @now = Time.now.to_f
7
+ @customer = Customer.new
8
+ @customer.custid = "test@example.com"
9
+ @customer.email = "test@example.com"
10
+ @customer.role = "user"
11
+ @customer.key = "abc123"
12
+ @customer.planid = "basic"
13
+ @customer.created = Time.now.to_i
14
+ @customer.updated = Time.now.to_i
15
+
16
+ ## Customer can be saved
17
+ @customer.save
18
+ #=> true
19
+
20
+ ## Customer can be retrieved by identifier
21
+ retrieved_customer = Customer.from_redis("test@example.com")
22
+ retrieved_customer.custid
23
+ #=> "test@example.com"
24
+
25
+ ## Customer fields can be accessed
26
+ @customer.email
27
+ #=> "test@example.com"
28
+
29
+ ## Customer role can be set and retrieved
30
+ @customer.role = "admin"
31
+ @customer.role
32
+ #=> "admin"
33
+
34
+ ## Customer can update fields
35
+ @customer.planid = "premium"
36
+ @customer.save
37
+ ident = @customer.identifier
38
+ Customer.from_redis(ident).planid
39
+ #=> "premium"
40
+
41
+ ## Customer can increment secrets_created counter
42
+ @customer.secrets_created.clear
43
+ @customer.secrets_created.increment
44
+ @customer.secrets_created.value
45
+ #=> '1'
46
+
47
+ ## Customer can add custom domain via add method
48
+ @customer.custom_domains.add(@now, "example.org")
49
+ @customer.custom_domains.members.include?("example.org")
50
+ #=> true
51
+
52
+ ## Customer can retrieve custom domain score via score method
53
+ @customer.custom_domains.score("example.org")
54
+ #=> @now
55
+
56
+ ## Customer can add custom domain via []= method
57
+ @customer.custom_domains["example2.org"] = @now
58
+ @customer.custom_domains.members.include?("example2.org")
59
+ #=> true
60
+
61
+ ## Customer can retrieve custom domain score via []
62
+ @customer.custom_domains["example.org"]
63
+ #=> @now
64
+
65
+
66
+ ## Customer can store timeline
67
+ @customer.timeline["last_login"] = @now
68
+ @customer.timeline["last_login"].to_i.positive?
69
+ #=> true
70
+
71
+ ## Customer can be added to class-level sorted set
72
+ Customer.instances << @customer
73
+ Customer.instances.member?(@customer)
74
+ #=> true
75
+
76
+ ## Customer can be removed from class-level sorted set
77
+ Customer.instances.delete(@customer)
78
+ Customer.instances.member?(@customer)
79
+ #=> false
80
+
81
+ ## Customer can add a session
82
+ @customer.sessions << "session123"
83
+ @customer.sessions.members.include?("session123")
84
+ #=> true
85
+
86
+ ## Customer can set and get password reset information
87
+ @customer.password_reset["token"] = "reset123"
88
+ @customer.password_reset["token"]
89
+ #=> "reset123"
90
+
91
+ ## Customer can be destroyed
92
+ ret = @customer.destroy!
93
+ cust = Customer.from_redis("test@example.com")
94
+ exists = Customer.exists?("test@example.com")
95
+ [ret, cust.nil?, exists]
96
+ #=> [true, true, false]
97
+
98
+ ## Customer.destroy! can be called on an already destroyed object
99
+ @customer.destroy!
100
+ #=> false
101
+
102
+ ## Customer.db returns the correct database number
103
+ Customer.db
104
+ #=> 15
105
+
106
+ ## Customer.db returns the correct database number
107
+ @customer.db
108
+ #=> 15
109
+
110
+ ## @customer.redis.connection returns the correct redis URI
111
+ @customer.redis.connection
112
+ #=> {:host=>"127.0.0.1", :port=>6379, :db=>15, :id=>"redis://127.0.0.1:6379/15", :location=>"127.0.0.1:6379"}
113
+
114
+ ## @customer.redis.uri returns the correct redis URI
115
+ @customer.secrets_created.db
116
+ #=> nil
117
+
118
+ ## @customer.redis.uri returns the correct redis URI
119
+ @customer.secrets_created.redis.connection
120
+ #=> {:host=>"127.0.0.1", :port=>6379, :db=>15, :id=>"redis://127.0.0.1:6379/15", :location=>"127.0.0.1:6379"}
121
+
122
+ ## Customer.url is nil by default
123
+ Customer.uri
124
+ #=> nil
125
+
126
+ ## Customer.destroy! makes only one call to Redis
127
+ RedisCommandCounter.count_commands { @customer.destroy! }
128
+ #=> 1
129
+
130
+ ## Customer.db returns the correct database number
131
+ Customer.instances.db
132
+ #=> nil
133
+
134
+ ## Customer.db returns the correct database number
135
+ Customer.instances.uri.to_s
136
+ #=> 'redis://127.0.0.1/15/'
137
+
138
+
139
+ # Teardown
140
+ Customer.instances.clear
@@ -0,0 +1,86 @@
1
+
2
+ require_relative '../lib/familia'
3
+ require_relative './test_helpers'
4
+
5
+ # Setup
6
+ @now = Time.now.to_i
7
+ @customer = Customer.new
8
+ @customer.custid = "test@example.com"
9
+ @customer.email = "test@example.com"
10
+ @customer.role = "user"
11
+ @customer.key = "abc123"
12
+ @customer.planid = "basic"
13
+ @customer.created = @now
14
+ @customer.updated = @now
15
+ @customer.verified = true
16
+ @customer.reset_requested = false
17
+ @customer.save
18
+ @safe_dump = @customer.safe_dump
19
+
20
+ ## Customer can be safely dumped
21
+ @safe_dump.keys.sort
22
+ #=> [:active, :created, :custid, :role, :secrets_created, :updated, :verified]
23
+
24
+ ## Safe dump includes correct custid
25
+ @safe_dump[:custid]
26
+ #=> "test@example.com"
27
+
28
+ ## Safe dump includes correct role
29
+ @safe_dump[:role]
30
+ #=> "user"
31
+
32
+ ## Safe dump includes correct verified status
33
+ @safe_dump[:verified]
34
+ #=> true
35
+
36
+ ## Safe dump includes correct created timestamp
37
+ @safe_dump[:created]
38
+ #=> @now
39
+
40
+ ## Safe dump includes correct updated timestamp
41
+ @safe_dump[:updated]
42
+ #=> @now
43
+
44
+ ## Safe dump includes correct secrets_created count
45
+ @customer.secrets_created.increment
46
+ @safe_dump = @customer.safe_dump
47
+ @safe_dump[:secrets_created]
48
+ #=> "2"
49
+
50
+ ## Safe dump includes correct active status when verified and not reset requested
51
+ @safe_dump[:active]
52
+ #=> true
53
+
54
+ ## Safe dump includes correct active status when not verified
55
+ @customer.verified = false
56
+ @customer.save
57
+ @safe_dump = @customer.safe_dump
58
+ @safe_dump[:active]
59
+ #=> false
60
+
61
+ ## Safe dump includes correct active status when reset requested
62
+ @customer.verified = true
63
+ @customer.reset_requested = true
64
+ @customer.save
65
+ @safe_dump = @customer.safe_dump
66
+ @safe_dump[:active]
67
+ #=> false
68
+
69
+ ## Safe dump excludes sensitive information (email)
70
+ @safe_dump.has_key?(:email)
71
+ #=> false
72
+
73
+ ## Safe dump excludes sensitive information (key)
74
+ @safe_dump.has_key?(:key)
75
+ #=> false
76
+
77
+ ## Safe dump excludes sensitive information (passphrase)
78
+ @safe_dump.has_key?(:passphrase)
79
+ #=> false
80
+
81
+ ## Safe dump excludes non-specified fields
82
+ @safe_dump.has_key?(:planid)
83
+ #=> false
84
+
85
+ # Teardown
86
+ @customer.destroy!
@@ -0,0 +1,186 @@
1
+ # rubocop:disable all
2
+
3
+ require 'digest'
4
+ require_relative '../lib/familia'
5
+
6
+ # ENV['FAMILIA_TRACE'] = '1'
7
+ #Familia.debug = true
8
+ Familia.enable_redis_logging = true
9
+ Familia.enable_redis_counter = true
10
+
11
+ class Bone < Familia::Horreum
12
+ identifier [:token, :name]
13
+ field :token
14
+ field :name
15
+ list :owners
16
+ set :tags
17
+ zset :metrics
18
+ hashkey :props
19
+ string :value, :default => "GREAT!"
20
+ end
21
+
22
+ class Blone < Familia::Horreum
23
+ feature :safe_dump
24
+ list :owners
25
+ set :tags
26
+ zset :metrics
27
+ hashkey :props
28
+ string :value, :default => "GREAT!"
29
+ end
30
+
31
+ class Customer < Familia::Horreum
32
+ db 15 # don't use Onetime's default DB
33
+ ttl 5.years
34
+
35
+ feature :safe_dump
36
+ #feature :api_version
37
+
38
+ # NOTE: The SafeDump mixin caches the safe_dump_field_map so updating this list
39
+ # with hot reloading in dev mode will not work. You will need to restart the
40
+ # server to see the changes.
41
+ @safe_dump_fields = [
42
+ :custid,
43
+ :role,
44
+ :verified,
45
+ :updated,
46
+ :created,
47
+
48
+ # NOTE: The secrets_created incrementer is null until the first secret
49
+ # is created. See CreateSecret for where the incrementer is called.
50
+ #
51
+ {secrets_created: ->(cust) { cust.secrets_created.value || 0 } },
52
+
53
+ # We use the hash syntax here since `:active?` is not a valid symbol.
54
+ {active: ->(cust) { cust.active? } }
55
+ ]
56
+
57
+ class_sorted_set :values, key: 'onetime:customer'
58
+ class_hashkey :domains
59
+
60
+ hashkey :stripe_customer
61
+ sorted_set :timeline
62
+ sorted_set :custom_domains
63
+
64
+ counter :secrets_created
65
+
66
+ identifier :custid
67
+
68
+ field :custid
69
+ field :sessid
70
+ field :email
71
+ field :role
72
+ field :key
73
+ field :passphrase_encryption
74
+ field :passphrase
75
+ field :verified
76
+ field :apitoken
77
+ field :planid
78
+ field :created
79
+ field :updated
80
+ field :reset_requested #=> Boolean
81
+
82
+ hashkey :password_reset #=> Familia::HashKey
83
+ list :sessions #=> Familia::List
84
+
85
+ class_list :customers, suffix: []
86
+ class_string :message
87
+
88
+ class_zset :instances, class: self, reference: true
89
+
90
+ def active?
91
+ verified && !reset_requested
92
+ end
93
+ end
94
+ @c = Customer.new
95
+ @c.custid = "d@example.com"
96
+
97
+ class Session < Familia::Horreum
98
+ db 14 # don't use Onetime's default DB
99
+ ttl 180.minutes
100
+
101
+ identifier :generate_id
102
+
103
+ field :sessid
104
+ field :shrimp
105
+ field :custid
106
+ field :useragent
107
+ field :key
108
+ field :authenticated
109
+ field :ipaddress
110
+ field :created
111
+ field :updated
112
+
113
+ def generate_id
114
+ @sessid ||= Familia.generate_id
115
+ @sessid
116
+ end
117
+
118
+ # The external identifier is used by the rate limiter to estimate a unique
119
+ # client. We can't use the session ID b/c the request agent can choose to
120
+ # not send cookies, or the user can clear their cookies (in both cases the
121
+ # session ID would change which would circumvent the rate limiter). The
122
+ # external identifier is a hash of the IP address and the customer ID
123
+ # which means that anonymous users from the same IP address are treated
124
+ # as the same client (as far as the limiter is concerned). Not ideal.
125
+ #
126
+ # To put it another way, the risk of colliding external identifiers is
127
+ # acceptable for the rate limiter, but not for the session data. Acceptable
128
+ # b/c the rate limiter is a temporary measure to prevent abuse, and the
129
+ # worse case scenario is that a user is rate limited when they shouldn't be.
130
+ # The session data is permanent and must be kept separate to avoid leaking
131
+ # data between users.
132
+ def external_identifier
133
+ elements = []
134
+ elements << ipaddress || 'UNKNOWNIP'
135
+ elements << custid || 'anon'
136
+ @external_identifier ||= Familia.generate_sha_hash(elements)
137
+ Familia.ld "[Session.external_identifier] sess identifier input: #{elements.inspect} (result: #{@external_identifier})"
138
+ @external_identifier
139
+ end
140
+
141
+ end
142
+ @s = Session.new
143
+
144
+ class CustomDomain < Familia::Horreum
145
+
146
+ class_sorted_set :values, key: 'onetime:customdomain:values'
147
+
148
+ identifier :derive_id
149
+
150
+ field :display_domain
151
+ field :custid
152
+ field :base_domain
153
+ field :subdomain
154
+ field :trd
155
+ field :tld
156
+ field :sld
157
+ field :txt_validation_host
158
+ field :txt_validation_value
159
+ field :status
160
+ field :vhost
161
+ field :verified
162
+ field :created
163
+ field :updated
164
+ field :_original_value
165
+
166
+ # Derive a unique identifier for the object based on the display domain and
167
+ # the customer ID. This is used to ensure that the same domain can't be
168
+ # added twice by the same customer while avoiding collisions between customers.
169
+ def derive_id
170
+ Familia.generate_sha_hash(:display_domain, :custid).slice(0, 8)
171
+ end
172
+ end
173
+ @d = CustomDomain.new
174
+ @d.display_domain = "example.com"
175
+ @d.custid = @c.custid
176
+
177
+ class Limiter < Familia::Horreum
178
+
179
+ identifier :name
180
+ field :name
181
+ string :counter, :ttl => 1.hour, :quantize => [10.minutes, '%H:%M', 1302468980]
182
+
183
+ def identifier
184
+ @name
185
+ end
186
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: familia
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.2
4
+ version: 1.0.0.pre.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Delano Mandelbaum
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-06-23 00:00:00.000000000 Z
11
+ date: 2024-08-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
@@ -45,47 +45,19 @@ dependencies:
45
45
  - !ruby/object:Gem::Version
46
46
  version: '1.3'
47
47
  - !ruby/object:Gem::Dependency
48
- name: gibbler
48
+ name: byebug
49
49
  requirement: !ruby/object:Gem::Requirement
50
50
  requirements:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: 1.0.0
54
- type: :runtime
55
- prerelease: false
56
- version_requirements: !ruby/object:Gem::Requirement
57
- requirements:
58
- - - "~>"
59
- - !ruby/object:Gem::Version
60
- version: 1.0.0
61
- - !ruby/object:Gem::Dependency
62
- name: storable
63
- requirement: !ruby/object:Gem::Requirement
64
- requirements:
65
- - - "~>"
66
- - !ruby/object:Gem::Version
67
- version: 0.10.0
68
- type: :runtime
69
- prerelease: false
70
- version_requirements: !ruby/object:Gem::Requirement
71
- requirements:
72
- - - "~>"
73
- - !ruby/object:Gem::Version
74
- version: 0.10.0
75
- - !ruby/object:Gem::Dependency
76
- name: multi_json
77
- requirement: !ruby/object:Gem::Requirement
78
- requirements:
79
- - - "~>"
80
- - !ruby/object:Gem::Version
81
- version: '1.15'
82
- type: :runtime
53
+ version: '11.0'
54
+ type: :development
83
55
  prerelease: false
84
56
  version_requirements: !ruby/object:Gem::Requirement
85
57
  requirements:
86
58
  - - "~>"
87
59
  - !ruby/object:Gem::Version
88
- version: '1.15'
60
+ version: '11.0'
89
61
  description: 'Familia: An ORM for Redis in Ruby.. Organize and store ruby objects
90
62
  in Redis'
91
63
  email: gems@solutious.com
@@ -96,6 +68,8 @@ files:
96
68
  - ".github/workflows/ruby.yml"
97
69
  - ".gitignore"
98
70
  - ".pre-commit-config.yaml"
71
+ - ".rubocop.yml"
72
+ - ".rubocop_todo.yml"
99
73
  - Gemfile
100
74
  - Gemfile.lock
101
75
  - LICENSE.txt
@@ -103,26 +77,55 @@ files:
103
77
  - VERSION.yml
104
78
  - familia.gemspec
105
79
  - lib/familia.rb
80
+ - lib/familia/base.rb
81
+ - lib/familia/connection.rb
106
82
  - lib/familia/core_ext.rb
107
- - lib/familia/helpers.rb
108
- - lib/familia/object.rb
109
- - lib/familia/redisobject.rb
110
- - lib/familia/test_helpers.rb
111
- - lib/familia/tools.rb
83
+ - lib/familia/errors.rb
84
+ - lib/familia/features.rb
85
+ - lib/familia/features/api_version.rb
86
+ - lib/familia/features/atomic_saves.rb
87
+ - lib/familia/features/quantizer.rb
88
+ - lib/familia/features/safe_dump.rb
89
+ - lib/familia/horreum.rb
90
+ - lib/familia/horreum/class_methods.rb
91
+ - lib/familia/horreum/commands.rb
92
+ - lib/familia/horreum/relations_management.rb
93
+ - lib/familia/horreum/serialization.rb
94
+ - lib/familia/horreum/settings.rb
95
+ - lib/familia/horreum/utils.rb
96
+ - lib/familia/logging.rb
97
+ - lib/familia/redistype.rb
98
+ - lib/familia/redistype/commands.rb
99
+ - lib/familia/redistype/serialization.rb
100
+ - lib/familia/settings.rb
101
+ - lib/familia/types/hashkey.rb
102
+ - lib/familia/types/list.rb
103
+ - lib/familia/types/sorted_set.rb
104
+ - lib/familia/types/string.rb
105
+ - lib/familia/types/unsorted_set.rb
106
+ - lib/familia/utils.rb
107
+ - lib/familia/version.rb
108
+ - lib/redis_middleware.rb
112
109
  - try/00_familia_try.rb
113
110
  - try/10_familia_try.rb
114
- - try/20_redis_object_try.rb
115
- - try/21_redis_object_zset_try.rb
116
- - try/22_redis_object_set_try.rb
117
- - try/23_redis_object_list_try.rb
118
- - try/24_redis_object_string_try.rb
119
- - try/25_redis_object_hash_try.rb
111
+ - try/20_redis_type_try.rb
112
+ - try/21_redis_type_zset_try.rb
113
+ - try/22_redis_type_set_try.rb
114
+ - try/23_redis_type_list_try.rb
115
+ - try/24_redis_type_string_try.rb
116
+ - try/25_redis_type_hash_try.rb
120
117
  - try/26_redis_bool_try.rb
118
+ - try/27_redis_horreum_try.rb
121
119
  - try/30_familia_object_try.rb
120
+ - try/35_feature_safedump_try.rb
121
+ - try/40_customer_try.rb
122
+ - try/41_customer_safedump_try.rb
123
+ - try/test_helpers.rb
122
124
  homepage: https://github.com/delano/familia
123
125
  licenses:
124
126
  - MIT
125
- metadata: {}
127
+ metadata:
128
+ rubygems_mfa_required: 'true'
126
129
  post_install_message:
127
130
  rdoc_options: []
128
131
  require_paths:
@@ -138,7 +141,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
138
141
  - !ruby/object:Gem::Version
139
142
  version: '0'
140
143
  requirements: []
141
- rubygems_version: 3.5.9
144
+ rubygems_version: 3.5.17
142
145
  signing_key:
143
146
  specification_version: 4
144
147
  summary: An ORM for Redis in Ruby.
@@ -1,70 +0,0 @@
1
-
2
- module Familia
3
- #
4
- # class Example
5
- # include Familia
6
- # field :name
7
- # include Familia::Stamps
8
- # end
9
- #
10
- module Stamps
11
- def self.included(obj)
12
- obj.module_eval do
13
- field :created => Integer
14
- field :updated => Integer
15
- def init_stamps
16
- now = Time.now.utc.to_i
17
- @created ||= now
18
- @updated ||= now
19
- end
20
- def created
21
- @created ||= Time.now.utc.to_i
22
- end
23
- def updated
24
- @updated ||= Time.now.utc.to_i
25
- end
26
- def created_age
27
- Time.now.utc.to_i-created
28
- end
29
- def updated_age
30
- Time.now.utc.to_i-updated
31
- end
32
- def update_time
33
- @updated = Time.now.utc.to_i
34
- end
35
- def update_time!
36
- update_time
37
- save if respond_to? :save
38
- @updated
39
- end
40
- end
41
- end
42
- end
43
- module Status
44
- def self.included(obj)
45
- obj.module_eval do
46
- field :status
47
- field :message
48
- def failure?() status? 'failure' end
49
- def success?() status? 'success' end
50
- def pending?() status? 'pending' end
51
- def expired?() status? 'expired' end
52
- def disabled?() status? 'disabled' end
53
- def failure!(msg=nil) status! 'failure', msg end
54
- def success!(msg=nil) status! 'success', msg end
55
- def pending!(msg=nil) status! 'pending', msg end
56
- def expired!(msg=nil) status! 'expired', msg end
57
- def disabled!(msg=nil) status! 'disabled', msg end
58
- private
59
- def status?(s)
60
- status.to_s == s.to_s
61
- end
62
- def status!(s, msg=nil)
63
- @updated = Time.now.utc.to_f
64
- @status, @message = s, msg
65
- save if respond_to? :save
66
- end
67
- end
68
- end
69
- end
70
- end