mondrian_redis_segment_cache 0.2.0-java → 0.3.0-java

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: 896185519afb0d52f37a79e5025257bdf5dfbc5c
4
- data.tar.gz: 1bb17d24bf9ff9b6e93a43ab6eea7b3d819bc937
3
+ metadata.gz: 97fcf8346cd45a212d99ccefbf418c46e2b8937a
4
+ data.tar.gz: 851f15a091b8d16065d8faa954b5df564d1e7f08
5
5
  SHA512:
6
- metadata.gz: 800116baba8a0b27f294f247543e81a970f5d73926e68e98ae3e03c48f77dd3aa59667b3ccf49d7d0ea3feb68d13988fa67e8f883d429e02181f320e247ae412
7
- data.tar.gz: 33828588996fb1ac33f1d7d598de0b8949c8ffe7f5845e1823556ab9c2db3bbcca0de964e65b8f52f9a6b43f845ae11341a9a44c82f51f4688c1b2209d9b868d
6
+ metadata.gz: e31c59458a901c35683e2fa250b37e3c5a6f75ab680087214f6802ace7db9b1f20031abceff1d12ba1804d2d43ef3d62153436bf7de755442c87d93ba0aeff13
7
+ data.tar.gz: 0a3a82cb519cbe868c8acac5e1cdc3fdc567218b81e660fa44d7c2e6d55ea5ab0e16959566948f276076908f299a13ec9af7cbb2048f3992e6c543bd22ac8d53
data/README.md CHANGED
@@ -7,15 +7,10 @@ examples of other implementations are in the links below.
7
7
  In order to use Mondrian with Redis (our preferred caching layer) and Ruby (our preferred language -- Jruby) we had
8
8
  to implement the SegmentCache interface from Mondrian and use the Redis notifications api.
9
9
 
10
- Mondrian's segment cache needs to be able to get/set/remove cache items and also get any updates from the caching server
11
- as other nodes are getting/setting/removing entries. This means that we need to use both the notifications and subscribe
12
- api's from Redis.
13
-
14
10
  http://stackoverflow.com/questions/17533594/implementing-a-mondrian-shared-segmentcache
15
11
  http://mondrian.pentaho.com/api/mondrian/spi/SegmentCache.html
16
12
  https://github.com/pentaho/mondrian/blob/master/src/main/mondrian/rolap/cache/MemorySegmentCache.java
17
13
  https://github.com/webdetails/cdc
18
- http://redis.io/topics/notifications
19
14
 
20
15
  ## Installation
21
16
 
@@ -47,19 +42,6 @@ MONDRIAN_SEGMENT_CACHE = ::MondrianRedisSegmentCache::Cache.new(MONDRIAN_REDIS_C
47
42
  ::Java::MondrianSpi::SegmentCache::SegmentCacheInjector::add_cache(MONDRIAN_SEGMENT_CACHE)
48
43
  ```
49
44
 
50
- In Redis we use the notifications api, so you must turn it on!
51
- It is off by default because it is a new feature and can be CPU intensive. Redis does a ton, so there is a minimum of notifications
52
- that must be turned on for this gem to work.
53
-
54
- `notify-keyspace-events Egex$`
55
-
56
- This tells Redis to publish keyevent events (which means we can subscribe to things like set/del) and to publish the generic commands
57
- (like DEL, EXPIRE) and finally String commands (like SET)
58
-
59
- The SegmentCache uses these notifications to keep Mondrian in sync across your Mondrian instances.
60
- It also eager loads the current cached items into the listeners when they are added to the cache. This allows
61
- an existing cache to be reused between deploys.
62
-
63
45
  Cache expiry is handled by the options `:ttl` and `:expires_at`
64
46
 
65
47
  If you want a static ttl (time to live) then each key that is inserted will be set to expire after the ttl completes. This is
@@ -1,4 +1,5 @@
1
1
  require 'redis'
2
+ require 'concurrent'
2
3
  require 'mondrian_redis_segment_cache/created_event'
3
4
  require 'mondrian_redis_segment_cache/deleted_event'
4
5
 
@@ -6,15 +7,8 @@ module MondrianRedisSegmentCache
6
7
  class Cache
7
8
  include Java::MondrianSpi::SegmentCache
8
9
 
9
- attr_reader :created_listener_connection,
10
- :deleted_listener_connection,
11
- :evicted_listener_connection,
12
- :expired_listener_connection,
13
- :created_listener_thread,
14
- :deleted_listener_thread,
15
- :evicted_listener_thread,
16
- :expired_listener_thread,
17
- :listeners,
10
+ attr_reader :listeners,
11
+ :local_cache_set,
18
12
  :mondrian_redis,
19
13
  :options
20
14
 
@@ -25,15 +19,22 @@ module MondrianRedisSegmentCache
25
19
  #
26
20
  def initialize(mondrian_redis_connection, new_options = {})
27
21
  @mondrian_redis = mondrian_redis_connection
28
- @created_listener_connection = ::Redis.new(client_options)
29
- @deleted_listener_connection = ::Redis.new(client_options)
30
- @evicted_listener_connection = ::Redis.new(client_options)
31
- @expired_listener_connection = ::Redis.new(client_options)
32
22
  @options = Marshal.load(Marshal.dump(new_options))
23
+ @listeners = Set.new
24
+ @local_cache_set = Set.new
25
+
26
+ ##
27
+ # Having a TimerTask reconcile every 5 minutes so the local listeners are eventually consistent with
28
+ # respect to what is in the cache and what has been done .... allows us to get rid of the event
29
+ # subscribers in the redis API ... consider the job to have timed out after 45 seconds
30
+ @reconcile_task = ::Concurrent::TimerTask.new(:execution_interval => 360, :timeout_interval => 45) do
31
+ reconcile_set_and_keys
32
+ reconcile_local_set_with_redis
33
+ end
33
34
 
34
- reset_listeners
35
- start
35
+ @reconcile_task.execute
36
36
  reconcile_set_and_keys
37
+ reconcile_local_set_with_redis
37
38
  end
38
39
 
39
40
  ##
@@ -41,52 +42,19 @@ module MondrianRedisSegmentCache
41
42
  #
42
43
  def addListener(segment_cache_listener)
43
44
  listeners << segment_cache_listener
44
- eager_load_listener(segment_cache_listener)
45
- end
46
-
47
- # returns boolean
48
- # takes mondrian.spi.SegmentHeader
49
- def contains(segment_header)
50
- segment_header.description # Hazel adapter says this affects serialization
51
- header_base64 = segment_header_to_base64(segment_header)
52
-
53
- if header_base64
54
- return mondrian_redis.exists(header_base64)
55
- end
56
-
57
- return false
58
- end
59
-
60
- def created_event_key
61
- @created_event_key ||= "__keyevent@#{client_options[:db]}__:set"
62
- end
63
-
64
- def deleted_event_key
65
- @deleted_event_key ||= "__keyevent@#{client_options[:db]}__:del"
66
- end
67
-
68
- def evicted_event_key
69
- @evicted_event_key ||= "__keyevent@#{client_options[:db]}__:evicted"
70
- end
71
-
72
- def expired_event_key
73
- @expired_event_key ||= "__keyevent@#{client_options[:db]}__:expired"
74
- end
75
-
76
- def eager_load_listener(listener)
77
- mondrian_redis.sscan_each(SEGMENT_HEADERS_SET_KEY) do |segment_header_base64|
78
- publish_created_to_listener(segment_header_base64, listener)
79
- end
80
45
  end
81
46
 
82
47
  # returns mondrian.spi.SegmentBody
83
48
  # takes mondrian.spi.SegmentHeader
84
49
  def get(segment_header)
85
- segment_header.description # Hazel adapter says this affects serialization
50
+ segment_header.getDescription # Hazel adapter says this affects serialization
86
51
  header_base64 = segment_header_to_base64(segment_header)
87
52
 
88
53
  if header_base64
89
- body_base64 = mondrian_redis.get(header_base64)
54
+ body_base64 = mondrian_redis.with do |connection|
55
+ connection.get(header_base64)
56
+ end
57
+
90
58
  return segment_body_from_base64(body_base64)
91
59
  end
92
60
 
@@ -97,83 +65,52 @@ module MondrianRedisSegmentCache
97
65
  def getSegmentHeaders()
98
66
  segment_headers = ::Java::JavaUtil::ArrayList.new
99
67
 
100
- mondrian_redis.sscan_each(SEGMENT_HEADERS_SET_KEY) do |segment_header_base64|
101
- segment_header = segment_header_from_base64(segment_header_base64)
102
-
103
- if segment_header
104
- segment_headers << segment_header
68
+ mondrian_redis.with do |connection|
69
+ connection.sscan_each(SEGMENT_HEADERS_SET_KEY) do |segment_header_base64|
70
+ segment_header = segment_header_from_base64(segment_header_base64)
71
+ segment_headers << segment_header if segment_header
105
72
  end
106
73
  end
107
74
 
108
75
  return segment_headers
109
76
  end
110
77
 
111
- def publish_created_to_listener(message, listener)
112
- segment_header = segment_header_from_base64(message)
113
-
114
- if segment_header
115
- created_event = ::MondrianRedisSegmentCache::CreatedEvent.new(segment_header)
116
- listener.handle(created_event)
117
- end
118
-
119
- check_listener_threads
120
- end
121
-
122
- def publish_created_to_listeners(message)
123
- listeners.each do |listener|
124
- publish_created_to_listener(message, listener)
125
- end
126
-
127
- check_listener_threads
128
- end
129
-
130
- def publish_deleted_to_listener(message, listener)
131
- segment_header = segment_header_from_base64(message)
132
-
133
- if segment_header
134
- deleted_event = ::MondrianRedisSegmentCache::DeletedEvent.new(segment_header)
135
- listener.handle(deleted_event)
136
- end
137
-
138
- check_listener_threads
139
- end
140
-
141
- def publish_deleted_to_listeners(message)
142
- listeners.each do |listener|
143
- publish_deleted_to_listener(message, listener)
144
- end
145
-
146
- # Each server can tell the Set to remove the key as it may be expired
147
- if mondrian_redis.sismember(SEGMENT_HEADERS_SET_KEY, message)
148
- mondrian_redis.srem(SEGMENT_HEADERS_SET_KEY, message)
149
- end
150
-
151
- check_listener_threads
152
- end
153
- alias_method :publish_evicted_to_listeners, :publish_deleted_to_listeners
154
- alias_method :publish_expired_to_listeners, :publish_deleted_to_listeners
155
-
156
78
  def put(segment_header, segment_body)
157
- segment_header.description # Hazel adapter says this affects serialization
79
+ set_success = nil
80
+ segment_header.getDescription # Hazel adapter says this affects serialization
158
81
  header_base64 = segment_header_to_base64(segment_header)
159
82
  body_base64 = segment_body_to_base64(segment_body)
160
- mondrian_redis.sadd(SEGMENT_HEADERS_SET_KEY, header_base64)
83
+ @local_cache_set << header_base64
84
+ mondrian_redis.with do |connection|
85
+ connection.sadd(SEGMENT_HEADERS_SET_KEY, header_base64)
86
+ end
161
87
 
162
88
  if has_expiry?
163
- set_success = mondrian_redis.setex(header_base64, expires_in_seconds, body_base64)
89
+ set_success = mondrian_redis.with do |connection|
90
+ connection.setex(header_base64, expires_in_seconds, body_base64)
91
+ end
164
92
  else
165
- set_success = mondrian_redis.set(header_base64, body_base64)
93
+ set_success = mondrian_redis.with do |connection|
94
+ connection.set(header_base64, body_base64)
95
+ end
166
96
  end
167
97
 
98
+ publish_created_to_listeners(header_base64)
168
99
  return ("#{set_success}".upcase == "OK" || set_success == true) # weird polymorphic return ?
169
100
  end
170
101
 
171
102
  def remove(segment_header)
172
- segment_header.description # Hazel adapter says this affects serialization
103
+ segment_header.getDescription # Hazel adapter says this affects serialization
173
104
  header_base64 = segment_header_to_base64(segment_header)
174
- mondrian_redis.srem(SEGMENT_HEADERS_SET_KEY, header_base64)
175
- deleted_keys = mondrian_redis.del(header_base64)
105
+ mondrian_redis.with do |connection|
106
+ connection.srem(SEGMENT_HEADERS_SET_KEY, header_base64)
107
+ end
108
+
109
+ deleted_keys = mondrian_redis.with do |connection|
110
+ connection.del(header_base64)
111
+ end
176
112
 
113
+ publish_deleted_to_listeners(header_base64)
177
114
  return deleted_keys >= 1
178
115
  end
179
116
 
@@ -181,35 +118,12 @@ module MondrianRedisSegmentCache
181
118
  listeners.delete(segment_cache_listener)
182
119
  end
183
120
 
184
- def reset_listeners
185
- @listeners = Set.new
186
- end
187
-
188
- def shutdown!
189
- # Ouch, why so harsh?
190
- created_listener_thread.kill if created_listener_thread && created_listener_thread.alive?
191
- deleted_listener_thread.kill if deleted_listener_thread && deleted_listener_thread.alive?
192
- evicted_listener_thread.kill if evicted_listener_thread && evicted_listener_thread.alive?
193
- expired_listener_thread.kill if expired_listener_thread && expired_listener_thread.alive?
194
- end
195
-
196
- def start
197
- check_listener_threads
198
- end
199
-
200
121
  def supportsRichIndex()
201
122
  true # this is why we are serializing the headers to base64
202
123
  end
203
124
 
204
125
  def tearDown()
205
- if options[:delete_all_on_tear_down]
206
- # Remove all of the headers and the set that controls them
207
- mondrian_redis.sscan_each(SEGMENT_HEADERS_SET_KEY) do |segment_header_base64|
208
- mondrian_redis.del(segment_header_base64)
209
- end
210
-
211
- mondrian_redis.del(SEGMENT_HEADERS_SET_KEY)
212
- end
126
+ #no-op
213
127
  end
214
128
 
215
129
  private
@@ -217,26 +131,6 @@ module MondrianRedisSegmentCache
217
131
  ##
218
132
  # Private Instance Methods
219
133
  #
220
- def check_listener_threads
221
- register_created_listener if !created_listener_thread.respond_to?(:alive?) || !created_listener_thread.alive?
222
- register_deleted_listener if !deleted_listener_thread.respond_to?(:alive?) || !deleted_listener_thread.alive?
223
- register_expired_listener if !expired_listener_thread.respond_to?(:alive?) || !expired_listener_thread.alive?
224
- register_evicted_listener if !evicted_listener_thread.respond_to?(:alive?) || !evicted_listener_thread.alive?
225
- end
226
-
227
- def client_options
228
- # Redis 3.0.4 does not have options where 3.1 does
229
- unless mondrian_redis.client.respond_to?(:options)
230
- class << mondrian_redis.client
231
- def options
232
- @options
233
- end
234
- end
235
- end
236
-
237
- return mondrian_redis.client.options
238
- end
239
-
240
134
  def expires_in_seconds
241
135
  return options[:ttl] if options[:ttl]
242
136
 
@@ -248,7 +142,7 @@ module MondrianRedisSegmentCache
248
142
  expires_at = ::Time.new(now.year, now.month, now.day, options[:expires_at])
249
143
  end
250
144
 
251
- difference_from_now = now.to_i - expires_at.to_i
145
+ difference_from_now = expires_at.to_i - now.to_i
252
146
 
253
147
  until difference_from_now > 0 do
254
148
  difference_from_now = difference_from_now + 86_400 # already passed today, move to time tomorrow
@@ -261,55 +155,74 @@ module MondrianRedisSegmentCache
261
155
  options.has_key?(:ttl) || options.has_key?(:expires_at)
262
156
  end
263
157
 
264
- def reconcile_set_and_keys
265
- mondrian_redis.sscan_each(SEGMENT_HEADERS_SET_KEY) do |segment_header_base64|
266
- # Spin through Header Set and remove any keys that are not in redis at all (they may have been deleted while offline)
267
- unless mondrian_redis.exists(segment_header_base64)
268
- mondrian_redis.srem(SEGMENT_HEADERS_SET_KEY, segment_header_base64)
269
- end
158
+ def publish_created_to_listener(message, listener)
159
+ segment_header = segment_header_from_base64(message)
160
+
161
+ if segment_header
162
+ created_event = ::MondrianRedisSegmentCache::CreatedEvent.new(segment_header)
163
+ listener.handle(created_event)
270
164
  end
271
165
  end
272
166
 
273
- def register_created_listener
274
- @created_listener_thread = Thread.new(created_listener_connection, self) do |created_redis_connection, mondrian_cache|
275
- created_redis_connection.subscribe(mondrian_cache.created_event_key) do |on|
276
- on.message do |channel, message|
277
- mondrian_cache.publish_created_to_listeners(message)
278
- end
279
- end
167
+ def publish_created_to_listeners(message)
168
+ listeners.each do |listener|
169
+ publish_created_to_listener(message, listener)
280
170
  end
281
171
  end
282
172
 
283
- def register_deleted_listener
284
- @deleted_listener_thread = Thread.new(deleted_listener_connection, self) do |deleted_redis_connection, mondrian_cache|
285
- deleted_redis_connection.subscribe(mondrian_cache.deleted_event_key) do |on|
286
- on.message do |channel, message|
287
- mondrian_cache.publish_deleted_to_listeners(message)
288
- end
289
- end
173
+ def publish_deleted_to_listener(message, listener)
174
+ segment_header = segment_header_from_base64(message)
175
+
176
+ if segment_header
177
+ deleted_event = ::MondrianRedisSegmentCache::DeletedEvent.new(segment_header)
178
+ listener.handle(deleted_event)
290
179
  end
291
180
  end
292
181
 
293
- def register_expired_listener
294
- @expired_listener_thread = Thread.new(expired_listener_connection, self) do |expired_redis_connection, mondrian_cache|
295
- expired_redis_connection.subscribe(mondrian_cache.expired_event_key) do |on|
296
- on.message do |channel, message|
297
- mondrian_cache.publish_expired_to_listeners(message)
298
- end
299
- end
182
+ def publish_deleted_to_listeners(message)
183
+ listeners.each do |listener|
184
+ publish_deleted_to_listener(message, listener)
300
185
  end
301
186
  end
302
187
 
303
- def register_evicted_listener
304
- @evicted_listener_thread = Thread.new(evicted_listener_connection, self) do |evicted_redis_connection, mondrian_cache|
305
- evicted_redis_connection.subscribe(mondrian_cache.evicted_event_key) do |on|
306
- on.message do |channel, message|
307
- mondrian_cache.publish_evicted_to_listeners(message)
308
- end
188
+ def reconcile_local_set_with_redis
189
+ remote_set = Set.new
190
+
191
+ mondrian_redis.with do |connection|
192
+ connection.sscan_each(SEGMENT_HEADERS_SET_KEY) do |segment_header_base64|
193
+ remote_set << segment_header_base64
309
194
  end
310
195
  end
196
+
197
+ remote_added_keys = remote_set - local_cache_set
198
+ remote_removed_keys = local_cache_set - remote_set
199
+
200
+ remote_added_keys.each do |remote_added_key|
201
+ @local_cache_set << remote_added_key
202
+ publish_created_to_listeners(remote_added_key)
203
+ end
204
+
205
+ remote_removed_keys.each do |remote_removed_key|
206
+ @local_cache_set.delete(remote_removed_key)
207
+ publish_deleted_to_listeners(remote_removed_key)
208
+ end
311
209
  end
312
210
 
211
+ def reconcile_set_and_keys
212
+ headers = []
213
+ mondrian_redis.with do |connection|
214
+ connection.sscan_each(SEGMENT_HEADERS_SET_KEY) do |segment_header_base64|
215
+ headers << segment_header_base64
216
+ end
217
+ end
218
+
219
+ mondrian_redis.with do |connection|
220
+ headers.each do |header|
221
+ # Spin through Header Set and remove any keys that are not in redis at all (they may have been deleted while offline)
222
+ connection.srem(SEGMENT_HEADERS_SET_KEY, header) unless connection.exists(header)
223
+ end
224
+ end
225
+ end
313
226
 
314
227
  def segment_body_from_base64(segment_body_base64)
315
228
  return nil unless segment_body_base64
@@ -1,3 +1,3 @@
1
1
  module MondrianRedisSegmentCache
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -21,6 +21,7 @@ Gem::Specification.new do |gem|
21
21
  gem.add_dependency "redis"
22
22
  gem.add_dependency "java_to_base64"
23
23
  gem.add_dependency "mondrian-olap"
24
+ gem.add_dependency "concurrent-ruby"
24
25
 
25
26
  gem.add_development_dependency "bundler"
26
27
  gem.add_development_dependency "mocha"
metadata CHANGED
@@ -1,113 +1,127 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mondrian_redis_segment_cache
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: java
6
6
  authors:
7
7
  - Brandon Dewitt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-09-19 00:00:00.000000000 Z
11
+ date: 2017-01-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
14
19
  name: redis
20
+ prerelease: false
21
+ type: :runtime
15
22
  version_requirements: !ruby/object:Gem::Requirement
16
23
  requirements:
17
- - - '>='
24
+ - - ">="
18
25
  - !ruby/object:Gem::Version
19
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
20
28
  requirement: !ruby/object:Gem::Requirement
21
29
  requirements:
22
- - - '>='
30
+ - - ">="
23
31
  - !ruby/object:Gem::Version
24
32
  version: '0'
33
+ name: java_to_base64
25
34
  prerelease: false
26
35
  type: :runtime
27
- - !ruby/object:Gem::Dependency
28
- name: java_to_base64
29
36
  version_requirements: !ruby/object:Gem::Requirement
30
37
  requirements:
31
- - - '>='
38
+ - - ">="
32
39
  - !ruby/object:Gem::Version
33
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
34
42
  requirement: !ruby/object:Gem::Requirement
35
43
  requirements:
36
- - - '>='
44
+ - - ">="
37
45
  - !ruby/object:Gem::Version
38
46
  version: '0'
47
+ name: mondrian-olap
39
48
  prerelease: false
40
49
  type: :runtime
41
- - !ruby/object:Gem::Dependency
42
- name: mondrian-olap
43
50
  version_requirements: !ruby/object:Gem::Requirement
44
51
  requirements:
45
- - - '>='
52
+ - - ">="
46
53
  - !ruby/object:Gem::Version
47
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
48
56
  requirement: !ruby/object:Gem::Requirement
49
57
  requirements:
50
- - - '>='
58
+ - - ">="
51
59
  - !ruby/object:Gem::Version
52
60
  version: '0'
61
+ name: concurrent-ruby
53
62
  prerelease: false
54
63
  type: :runtime
55
- - !ruby/object:Gem::Dependency
56
- name: bundler
57
64
  version_requirements: !ruby/object:Gem::Requirement
58
65
  requirements:
59
- - - '>='
66
+ - - ">="
60
67
  - !ruby/object:Gem::Version
61
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
62
70
  requirement: !ruby/object:Gem::Requirement
63
71
  requirements:
64
- - - '>='
72
+ - - ">="
65
73
  - !ruby/object:Gem::Version
66
74
  version: '0'
75
+ name: bundler
67
76
  prerelease: false
68
77
  type: :development
69
- - !ruby/object:Gem::Dependency
70
- name: mocha
71
78
  version_requirements: !ruby/object:Gem::Requirement
72
79
  requirements:
73
- - - '>='
80
+ - - ">="
74
81
  - !ruby/object:Gem::Version
75
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
76
84
  requirement: !ruby/object:Gem::Requirement
77
85
  requirements:
78
- - - '>='
86
+ - - ">="
79
87
  - !ruby/object:Gem::Version
80
88
  version: '0'
89
+ name: mocha
81
90
  prerelease: false
82
91
  type: :development
83
- - !ruby/object:Gem::Dependency
84
- name: pry
85
92
  version_requirements: !ruby/object:Gem::Requirement
86
93
  requirements:
87
- - - '>='
94
+ - - ">="
88
95
  - !ruby/object:Gem::Version
89
96
  version: '0'
97
+ - !ruby/object:Gem::Dependency
90
98
  requirement: !ruby/object:Gem::Requirement
91
99
  requirements:
92
- - - '>='
100
+ - - ">="
93
101
  - !ruby/object:Gem::Version
94
102
  version: '0'
103
+ name: pry
95
104
  prerelease: false
96
105
  type: :development
97
- - !ruby/object:Gem::Dependency
98
- name: rake
99
106
  version_requirements: !ruby/object:Gem::Requirement
100
107
  requirements:
101
- - - '>='
108
+ - - ">="
102
109
  - !ruby/object:Gem::Version
103
110
  version: '0'
111
+ - !ruby/object:Gem::Dependency
104
112
  requirement: !ruby/object:Gem::Requirement
105
113
  requirements:
106
- - - '>='
114
+ - - ">="
107
115
  - !ruby/object:Gem::Version
108
116
  version: '0'
117
+ name: rake
109
118
  prerelease: false
110
119
  type: :development
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
111
125
  description: Segment Cache for Mondrian written in JRuby with Redis as the cache store
112
126
  email:
113
127
  - brandonsdewitt@gmail.com
@@ -115,7 +129,7 @@ executables: []
115
129
  extensions: []
116
130
  extra_rdoc_files: []
117
131
  files:
118
- - .gitignore
132
+ - ".gitignore"
119
133
  - Gemfile
120
134
  - LICENSE.txt
121
135
  - README.md
@@ -137,17 +151,17 @@ require_paths:
137
151
  - lib
138
152
  required_ruby_version: !ruby/object:Gem::Requirement
139
153
  requirements:
140
- - - '>='
154
+ - - ">="
141
155
  - !ruby/object:Gem::Version
142
156
  version: '0'
143
157
  required_rubygems_version: !ruby/object:Gem::Requirement
144
158
  requirements:
145
- - - '>='
159
+ - - ">="
146
160
  - !ruby/object:Gem::Version
147
161
  version: '0'
148
162
  requirements: []
149
163
  rubyforge_project:
150
- rubygems_version: 2.2.2
164
+ rubygems_version: 2.4.8
151
165
  signing_key:
152
166
  specification_version: 4
153
167
  summary: Segment Cache for Mondrian written in JRuby with Redis as the cache store