instantcache 0.1.0a1 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,4 +1,11 @@
1
- === 0.0.1 2011-08-25
1
+ === 0.1.1 2011-09-09
2
+
3
+ * 1 major enhancement:
4
+ * Added check for the cache object having been set up.
5
+ - Minor enhancements
6
+ - Much documentation updating.
7
+
8
+ === 0.1.0a1 2011-09-08
2
9
 
3
10
  * 1 major enhancement:
4
11
  * Initial release
data/README.txt CHANGED
@@ -1,28 +1,65 @@
1
1
  = InstantCache - Variables in memcached
2
2
 
3
- * http://github.com/RoUS/rubygem-instantcache
3
+ * http://instantcache.rubyforge.org/
4
+
5
+ * github: http://github.com/RoUS/rubygem-instantcache
6
+ * rubyforge: http://rubyforge.org/scm/?group_id=10054
4
7
 
5
8
  == DESCRIPTION:
6
9
 
7
- rubygem-instantcache provides the InstantCache module, a mixin
10
+ *rubygem-instantcache* provides the InstantCache module, a mixin
8
11
  which has accessors that allow you to declare 'instance variables'
9
12
  that are actually stored in a memcached cluster rather than
10
13
  local memory.
11
14
 
15
+ == GLOSSARY:
16
+
17
+ * <b><i>blob</i></b>, <b><i>blob object</i></b>, or <b><i>blob instance</i></b>: An instrumented InstantCache::Blob or InstantCache::Counter object that has been instantiated and stored in an <i>instance variable</i>.
18
+ * <b><i>cached value</i></b>: The value actually stored in the memcached cluster.
19
+ * <b><i>cache</i></b> (or <b><i>cached</i></b>) <b><i>variable</i></b>: an instance variable declared with one of the <tt>memcached_<i>xxx</i></tt> declarators and holding a <i>blob instance</i>.
20
+ * <b><i>cell</i></b> or <b><i>cache cell</i></b>: The named location in the memcached cluster where a <i>cached value</i> is stored.
21
+ * <b><i>instance variable</i></b>: This has its canonical meaning: a named cell local to an object. <i>Blob objects</i> are stored in <i>instance variables</i> to form <i>cached variables</i>.
22
+
12
23
  == FEATURES:
13
24
 
14
- * Provides ''memcached_reader'', ''memcached_accessor'', and ''memcached_counter'' accessor declarations.
15
- * Variables declared with ''memcached_counter'' are restricted to integer values, and are incrementable/decrementable atomically.
16
- * Variables may be shared, using cells in memcache named by the user, or may be private, with opaque names unique to each instance.
17
- * Variables may be locked and unlocked for atomic operations.
25
+ * Provides <tt>memcached_reader</tt>, <tt>memcached_accessor</tt>, and <tt>memcached_counter</tt> accessor declarations.
26
+ * Cached variables declared with <tt>memcached_counter</tt> are restricted to integer values, and are incrementable/decrementable atomically.
27
+ * Cached variables may be shared, using cells in memcache named by the user, or may be private, with opaque names unique to each instance.
28
+ * Cached variables may be locked and unlocked for atomic operations.
29
+ * If an instance variable is inadvertently overwritten, a new connexion to the cached value will be created (a new blob object will be instantiated) the next time one of InstantCache's methods is used to access it.
30
+
31
+ == CAVEATS AND WARNINGS
18
32
 
19
- == PROBLEMS:
33
+ * InstantCache works by storing a specially-instrumented object in the actual instance variable. References from within the class to an instance variable declared as a cached variable should use the "<tt>self.</tt>" prefix (<i>e.g.</i>, <tt>self.ivar</tt>) or the blob object's methods directly (<i>e.g.</i>, <tt>@ivar.get</tt> or <tt>@ivar.set(17)</tt>).
34
+ * Direct assignment to an instance variable (<i>e.g.</i>, <tt>@ivar = 17</tt>) will lose the instrumented object and result in a new one being created.
20
35
 
21
- * Multiple references to a cached variable can get out of sync, leading to confusion if they are updated independently.
36
+ == KNOWN PROBLEMS:
37
+
38
+ * If an cached variable is locked, and is then re-instantiated/reconnected, the variable will <b>remain</b> locked and cannot be unlocked.
39
+ * Multiple references to a cached variable can get out of sync, leading to confusion if they are updated independently. That is,
40
+ class Foo
41
+ include InstantCache
42
+ memcached_accessor(:ivar)
43
+ end
44
+
45
+ f = Foo.new
46
+ f.ivar = [1,2,3]
47
+ copy = f.ivar
48
+ f.ivar = 17
49
+ copy
50
+ => [1,2,3]
51
+ f.ivar
52
+ => 17
53
+ copy << 4
54
+ => [1,2,3,4]
55
+ f.ivar
56
+ => [1,2,3,4]
22
57
 
23
58
  == SYNOPSIS:
24
59
 
60
+ require 'memcache'
25
61
  require 'instantcache'
62
+
26
63
  class Foo
27
64
  include InstantCache
28
65
  memcached_counter(:c1) # defaults to 0 if not already existant
@@ -56,8 +93,8 @@ local memory.
56
93
 
57
94
  == REQUIREMENTS:
58
95
 
59
- * Gem ''versionomy''
60
- * Gem ''memcache-client''
96
+ * Gem <tt>{versionomy}[https://rubygems.org/gems/versionomy]</tt>
97
+ * Gem <tt>{memcache-client}[https://rubygems.org/gems/memcache-client]</tt>
61
98
 
62
99
  == INSTALL:
63
100
 
data/instantcache.gemspec CHANGED
@@ -1,29 +1,25 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
3
  Gem::Specification.new do |s|
4
- s.name = %q{instantcache}
5
- s.version = "0.1.0a1"
4
+ s.name = "instantcache"
5
+ s.version = "0.1.1"
6
6
 
7
- s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.3.1") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Ken Coar"]
9
- s.date = %q{2011-09-08}
10
- s.description = %q{rubygem-instantcache provides the InstantCache module, a mixin
11
- which has accessors that allow you to declare 'instance variables'
12
- that are actually stored in a memcached cluster rather than
13
- local memory.}
9
+ s.date = "2011-09-09"
10
+ s.description = "rubygem-instantcache provides the InstantCache module, a mixin\nwhich has accessors that allow you to declare 'instance variables'\nthat are actually stored in a memcached cluster rather than\nlocal memory."
14
11
  s.email = ["coar@rubyforge.org"]
15
12
  s.extra_rdoc_files = ["History.txt", "LICENCE.txt", "Manifest.txt", "README.txt"]
16
- s.files = ["History.txt", "LICENCE.txt", "Manifest.txt", "README.txt", "Rakefile", "instantcache.gemspec", "lib/instantcache.rb", "lib/instantcache/exceptions.rb", "script/console", "script/destroy", "script/generate", "test/test_helper.rb", "test/test_instantcache.rb", "test/test_sharing_complex.rb", "test/test_sharing_simple.rb"]
17
- s.homepage = %q{http://github.com/RoUS/rubygem-instantcache}
13
+ s.files = ["History.txt", "LICENCE.txt", "Manifest.txt", "README.txt", "Rakefile", "instantcache.gemspec", "lib/instantcache.rb", "lib/instantcache/exceptions.rb", "script/console", "script/destroy", "script/generate", "test/test_helper.rb", "test/test_instantcache.rb", "test/test_sharing_complex.rb", "test/test_sharing_simple.rb", ".gemtest"]
14
+ s.homepage = "http://instantcache.rubyforge.org/"
18
15
  s.rdoc_options = ["--main", "README.txt"]
19
16
  s.require_paths = ["lib"]
20
- s.rubyforge_project = %q{instantcache}
21
- s.rubygems_version = %q{1.3.7}
22
- s.summary = %q{rubygem-instantcache provides the InstantCache module, a mixin which has accessors that allow you to declare 'instance variables' that are actually stored in a memcached cluster rather than local memory.}
17
+ s.rubyforge_project = "instantcache"
18
+ s.rubygems_version = "1.8.10"
19
+ s.summary = "rubygem-instantcache provides the InstantCache module, a mixin which has accessors that allow you to declare 'instance variables' that are actually stored in a memcached cluster rather than local memory."
23
20
  s.test_files = ["test/test_instantcache.rb", "test/test_helper.rb", "test/test_sharing_simple.rb", "test/test_sharing_complex.rb"]
24
21
 
25
22
  if s.respond_to? :specification_version then
26
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
27
23
  s.specification_version = 3
28
24
 
29
25
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
data/lib/instantcache.rb CHANGED
@@ -73,7 +73,7 @@ module InstantCache
73
73
  #
74
74
  # The base Versionomy representation of the package version.
75
75
  #
76
- Version = Versionomy.parse('0.1.0a1')
76
+ Version = Versionomy.parse('0.1.1')
77
77
 
78
78
  #
79
79
  # The package version-as-a-string.
@@ -102,6 +102,27 @@ module InstantCache
102
102
 
103
103
  #
104
104
  # === Description
105
+ # Wrapper for the @cache_object class variable.
106
+ #
107
+ # :call-seq:
108
+ # InstantCache.cache.<i>method</i>
109
+ #
110
+ # === Arguments
111
+ # <i>None.</i>
112
+ #
113
+ # === Exceptions
114
+ # [<tt>InstantCache::NoCache</tt>] Cache object unset or misset.
115
+ #
116
+ def cache # :nodoc
117
+ mco = (InstantCache.cache_object ||= nil)
118
+ return mco if (mco.kind_of?(MemCache))
119
+ raise NoCache
120
+ end
121
+
122
+ #
123
+ # === Description
124
+ # Add singleton wrapper methods to a copy of the cached value.
125
+ #
105
126
  # :call-seq:
106
127
  # InstantCache.enwrap(<i>cacheval</i>) => nil
107
128
  #
@@ -451,7 +472,7 @@ module InstantCache
451
472
  #
452
473
  # TODO: This can mess with subclassing; need better way to find the cache
453
474
  #
454
- InstantCache.cache_object.set(self.name, rval, self.expiry, self.rawmode)
475
+ InstantCache.cache.set(self.name, rval, self.expiry, self.rawmode)
455
476
  return rval
456
477
  end
457
478
 
@@ -570,7 +591,7 @@ module InstantCache
570
591
  #
571
592
  # TODO: Another instance of poor-man's-cache-location; see #reset
572
593
  #
573
- sts = InstantCache.cache_object.add(self.lock_name, @identity)
594
+ sts = InstantCache.cache.add(self.lock_name, @identity)
574
595
  @locked_by_us = (sts.to_s =~ %r!^STORED!) ? true : false
575
596
  return @locked_by_us
576
597
  end
@@ -610,7 +631,7 @@ module InstantCache
610
631
  #
611
632
  # TODO: Another instance of poor-man's-cache-location; see #reset
612
633
  #
613
- sts = InstantCache.cache_object.get(self.lock_name) || false
634
+ sts = InstantCache.cache.get(self.lock_name) || false
614
635
  if (@locked_by_us && (sts != @identity))
615
636
  #
616
637
  # If we show we have the lock, but the lock cell doesn't exist
@@ -626,7 +647,7 @@ module InstantCache
626
647
  #
627
648
  # TODO: Another instance of poor-man's-cache-location; see #reset
628
649
  #
629
- sts = InstantCache.cache_object.delete(self.lock_name)
650
+ sts = InstantCache.cache.delete(self.lock_name)
630
651
  if (sts !~ %r!^DELETED!)
631
652
  e = LockInconsistency.new(self.lock_name,
632
653
  '/DELETED/',
@@ -656,7 +677,7 @@ module InstantCache
656
677
  #
657
678
  # TODO: Another instance of poor-man's-cache-location; see #reset
658
679
  #
659
- value = InstantCache.cache_object.get(self.name, self.rawmode)
680
+ value = InstantCache.cache.get(self.name, self.rawmode)
660
681
  begin
661
682
  #
662
683
  # Make a copy of the thing we fetched out of the cache.
@@ -717,8 +738,8 @@ module InstantCache
717
738
  #
718
739
  # We use both memcache#add and memcache#set for completeness.
719
740
  #
720
- InstantCache.cache_object.add(self.name, val, self.expiry, self.rawmode)
721
- InstantCache.cache_object.set(self.name, val, self.expiry, self.rawmode)
741
+ InstantCache.cache.add(self.name, val, self.expiry, self.rawmode)
742
+ InstantCache.cache.set(self.name, val, self.expiry, self.rawmode)
722
743
  #
723
744
  # Return the value as fetched through our accessor; this ensures
724
745
  # the proper annotation.
@@ -746,27 +767,6 @@ module InstantCache
746
767
  return self.get.__send__(:to_s, *args)
747
768
  end
748
769
 
749
- =begin
750
- #
751
- # === Description
752
- # :call-seq:
753
- # === Arguments
754
- # === Exceptions
755
- # <i>None.</i>
756
- #
757
- def method_missing(meth, *args)
758
- methsym = meth.to_sym
759
- return self.__send__(methsym, *args) if (self.respond_to?(methsym))
760
- curval = self.get
761
- lastval = curval.clone
762
- opresult = curval.__send__(methsym, *args)
763
- if (curval != lastval)
764
- self.set(curval)
765
- end
766
- return opresult
767
- end
768
- =end
769
-
770
770
  end # End of class Blob
771
771
 
772
772
  #
@@ -965,7 +965,7 @@ module InstantCache
965
965
  #
966
966
  # TODO: Another instance of poor-man's-cache-location; see #reset
967
967
  #
968
- return InstantCache.cache_object.incr(self.name, amt)
968
+ return InstantCache.cache.incr(self.name, amt)
969
969
  end
970
970
  alias_method(:incr, :increment)
971
971
 
@@ -999,7 +999,7 @@ module InstantCache
999
999
  #
1000
1000
  # TODO: Another instance of poor-man's-cache-location; see #reset
1001
1001
  #
1002
- return InstantCache.cache_object.decr(self.name, amt)
1002
+ return InstantCache.cache.decr(self.name, amt)
1003
1003
  end
1004
1004
  alias_method(:decr, :decrement)
1005
1005
 
@@ -1018,6 +1018,23 @@ module InstantCache
1018
1018
  # String constant used to set up most of the background magic
1019
1019
  # common to all of our types of cached variables.
1020
1020
  #
1021
+ # TODO: Resolve what to do if the instance variable is zapped
1022
+ #
1023
+ # One of the fortunate side-effects of all of the methods calling
1024
+ # this first is that if the instance variable gets zapped somehow,
1025
+ # the next access to it through of of our methods will create a
1026
+ # new Blob or Counter object and put it into the instance variable
1027
+ # before proceeding.
1028
+ #
1029
+ # One of the UNfortunate side effects of *that* is that if the
1030
+ # object that was lost was locked, it cannot be unlocked through
1031
+ # the normal paths -- only the blob object itself is supposed to
1032
+ # lock and unlock itself. It can be worked around, but that's for
1033
+ # another day.
1034
+ #
1035
+ # If we decide against instantiating a new object, the ConnexionLost
1036
+ # exception is ready to be pressed into service.
1037
+ #
1021
1038
  Setup =<<-'EOT' # :nodoc:
1022
1039
  def _initialise_%s
1023
1040
  unless (self.instance_variables.include?('@%s') \
@@ -1046,8 +1063,8 @@ module InstantCache
1046
1063
  unless (shared)
1047
1064
  mvar.reset
1048
1065
  finaliser = Proc.new {
1049
- InstantCache.cache_object.delete(mvar.name)
1050
- InstantCache.cache_object.delete(mvar.send(:lock_name))
1066
+ InstantCache.cache.delete(mvar.name)
1067
+ InstantCache.cache.delete(mvar.send(:lock_name))
1051
1068
  }
1052
1069
  ObjectSpace.define_finalizer(owner, finaliser)
1053
1070
  end
@@ -137,6 +137,24 @@ module InstantCache
137
137
  ]
138
138
  end # End of class IncompleteException
139
139
 
140
+ #
141
+ # Obviously this package is dependent upon memcache being available
142
+ # and configured. Gritch otherwise.
143
+ #
144
+ class NoCache < InstantCache::Exception
145
+ #
146
+ # ==== <tt>raise NoCache</tt>
147
+ # => InstantCache::NoCache: InstantCache.cache_object not initialised
148
+ #
149
+ # ==== <tt>raise Destroyed.new('<i>arg</i>')</tt>
150
+ # => InstantCache::NoCache: InstantCache.cache_object not initialised for "arg"
151
+ #
152
+ MessageFormat = [
153
+ 'InstantCache.cache_object not initialised',
154
+ 'InstantCache.cache_object not initialised for "%s"',
155
+ ]
156
+ end # End of class NoCache
157
+
140
158
  #
141
159
  # Once a variable has been hit by the 'destroy!' method, it
142
160
  # becomes inaccessible to the instance.
@@ -155,6 +173,25 @@ module InstantCache
155
173
  ]
156
174
  end # End of class Destroyed
157
175
 
176
+ #
177
+ # If the instance variable is somehow overwritten, the methods that
178
+ # try to treat it as a Blob or Counter will fail. This exception
179
+ # tries to make that failure less mysterious.
180
+ #
181
+ class ConnexionLost < InstantCache::Exception
182
+ #
183
+ # ==== <tt>raise ConnexionLost</tt>
184
+ # => InstantCache::ConnexionLost: instance variable no longer connected to cache
185
+ #
186
+ # ==== <tt>raise Destroyed.new('<i>arg</i>')</tt>
187
+ # => InstantCache::ConnexionLost: instance variable "@arg" no longer connected to cache
188
+ #
189
+ MessageFormat = [
190
+ 'instance variable no longer connected to cache',
191
+ 'instance variable "@%s" no longer connected to cache',
192
+ ]
193
+ end # End of class ConnexionLost
194
+
158
195
  #
159
196
  # Our record of the locked status of a cell differs from the information
160
197
  # stored in the memcache about it. This Is Not Good.
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: instantcache
3
3
  version: !ruby/object:Gem::Version
4
- hash: 415506520
5
- prerelease: true
4
+ hash: 25
5
+ prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 0a1
10
- version: 0.1.0a1
9
+ - 1
10
+ version: 0.1.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Ken Coar
@@ -15,8 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-09-08 00:00:00 -04:00
19
- default_executable:
18
+ date: 2011-09-09 00:00:00 Z
20
19
  dependencies:
21
20
  - !ruby/object:Gem::Dependency
22
21
  name: versionomy
@@ -66,7 +65,7 @@ dependencies:
66
65
  type: :development
67
66
  version_requirements: *id003
68
67
  description: |-
69
- rubygem-instantcache provides the InstantCache module, a mixin
68
+ *rubygem-instantcache* provides the InstantCache module, a mixin
70
69
  which has accessors that allow you to declare 'instance variables'
71
70
  that are actually stored in a memcached cluster rather than
72
71
  local memory.
@@ -98,8 +97,7 @@ files:
98
97
  - test/test_sharing_complex.rb
99
98
  - test/test_sharing_simple.rb
100
99
  - .gemtest
101
- has_rdoc: true
102
- homepage: http://github.com/RoUS/rubygem-instantcache
100
+ homepage: http://instantcache.rubyforge.org/
103
101
  licenses: []
104
102
 
105
103
  post_install_message:
@@ -120,21 +118,19 @@ required_ruby_version: !ruby/object:Gem::Requirement
120
118
  required_rubygems_version: !ruby/object:Gem::Requirement
121
119
  none: false
122
120
  requirements:
123
- - - ">"
121
+ - - ">="
124
122
  - !ruby/object:Gem::Version
125
- hash: 25
123
+ hash: 3
126
124
  segments:
127
- - 1
128
- - 3
129
- - 1
130
- version: 1.3.1
125
+ - 0
126
+ version: "0"
131
127
  requirements: []
132
128
 
133
129
  rubyforge_project: instantcache
134
- rubygems_version: 1.3.7
130
+ rubygems_version: 1.8.10
135
131
  signing_key:
136
132
  specification_version: 3
137
- summary: rubygem-instantcache provides the InstantCache module, a mixin which has accessors that allow you to declare 'instance variables' that are actually stored in a memcached cluster rather than local memory.
133
+ summary: "*rubygem-instantcache* provides the InstantCache module, a mixin which has accessors that allow you to declare 'instance variables' that are actually stored in a memcached cluster rather than local memory."
138
134
  test_files:
139
135
  - test/test_instantcache.rb
140
136
  - test/test_helper.rb