instantcache 0.1.0a1 → 0.1.1

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