gotime-cassandra_object 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/CHANGELOG +3 -0
  2. data/Gemfile +14 -0
  3. data/Gemfile.lock +42 -0
  4. data/LICENSE +13 -0
  5. data/README.markdown +79 -0
  6. data/Rakefile +74 -0
  7. data/TODO +2 -0
  8. data/VERSION +1 -0
  9. data/gotime-cassandra_object.gemspec +134 -0
  10. data/lib/cassandra_object.rb +13 -0
  11. data/lib/cassandra_object/associations.rb +35 -0
  12. data/lib/cassandra_object/associations/one_to_many.rb +136 -0
  13. data/lib/cassandra_object/associations/one_to_one.rb +77 -0
  14. data/lib/cassandra_object/attributes.rb +93 -0
  15. data/lib/cassandra_object/base.rb +97 -0
  16. data/lib/cassandra_object/callbacks.rb +10 -0
  17. data/lib/cassandra_object/collection.rb +8 -0
  18. data/lib/cassandra_object/cursor.rb +86 -0
  19. data/lib/cassandra_object/dirty.rb +27 -0
  20. data/lib/cassandra_object/identity.rb +61 -0
  21. data/lib/cassandra_object/identity/abstract_key_factory.rb +36 -0
  22. data/lib/cassandra_object/identity/key.rb +20 -0
  23. data/lib/cassandra_object/identity/natural_key_factory.rb +51 -0
  24. data/lib/cassandra_object/identity/uuid_key_factory.rb +37 -0
  25. data/lib/cassandra_object/indexes.rb +129 -0
  26. data/lib/cassandra_object/log_subscriber.rb +17 -0
  27. data/lib/cassandra_object/migrations.rb +72 -0
  28. data/lib/cassandra_object/mocking.rb +15 -0
  29. data/lib/cassandra_object/persistence.rb +195 -0
  30. data/lib/cassandra_object/serialization.rb +6 -0
  31. data/lib/cassandra_object/type_registration.rb +7 -0
  32. data/lib/cassandra_object/types.rb +128 -0
  33. data/lib/cassandra_object/validation.rb +49 -0
  34. data/test/basic_scenarios_test.rb +243 -0
  35. data/test/callbacks_test.rb +19 -0
  36. data/test/config/cassandra.in.sh +53 -0
  37. data/test/config/log4j.properties +38 -0
  38. data/test/config/storage-conf.xml +221 -0
  39. data/test/connection.rb +25 -0
  40. data/test/cursor_test.rb +66 -0
  41. data/test/dirty_test.rb +34 -0
  42. data/test/fixture_models.rb +90 -0
  43. data/test/identity/natural_key_factory_test.rb +94 -0
  44. data/test/index_test.rb +69 -0
  45. data/test/legacy/test_helper.rb +18 -0
  46. data/test/migration_test.rb +21 -0
  47. data/test/one_to_many_associations_test.rb +163 -0
  48. data/test/test_case.rb +28 -0
  49. data/test/test_helper.rb +16 -0
  50. data/test/time_test.rb +32 -0
  51. data/test/types_test.rb +252 -0
  52. data/test/validation_test.rb +25 -0
  53. data/test/z_mock_test.rb +36 -0
  54. metadata +243 -0
data/CHANGELOG ADDED
@@ -0,0 +1,3 @@
1
+ v 0.5.0.pre
2
+ - First release
3
+ - Rough around the corners, especially outside the core attributes/persistence stuff
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source :gemcutter
2
+
3
+ gem "activesupport", "~>3"
4
+ gem "activemodel", "~>3"
5
+
6
+ gem "cassandra"
7
+ gem "nokogiri"
8
+
9
+ group :development do
10
+ gem "shoulda", ">= 0"
11
+ gem "bundler", "~> 1.0.0"
12
+ gem "jeweler", "~> 1.5.1"
13
+ gem "rcov", ">= 0"
14
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,42 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activemodel (3.0.3)
5
+ activesupport (= 3.0.3)
6
+ builder (~> 2.1.2)
7
+ i18n (~> 0.4)
8
+ activesupport (3.0.3)
9
+ builder (2.1.2)
10
+ cassandra (0.9.0)
11
+ json
12
+ rake
13
+ simple_uuid (>= 0.1.0)
14
+ thrift_client (>= 0.6.0)
15
+ git (1.2.5)
16
+ i18n (0.5.0)
17
+ jeweler (1.5.1)
18
+ bundler (~> 1.0.0)
19
+ git (>= 1.2.5)
20
+ rake
21
+ json (1.4.6)
22
+ nokogiri (1.4.4)
23
+ rake (0.8.7)
24
+ rcov (0.9.9)
25
+ shoulda (2.11.3)
26
+ simple_uuid (0.1.1)
27
+ thrift (0.5.0)
28
+ thrift_client (0.6.0)
29
+ thrift (~> 0.5.0)
30
+
31
+ PLATFORMS
32
+ ruby
33
+
34
+ DEPENDENCIES
35
+ activemodel (~> 3)
36
+ activesupport (~> 3)
37
+ bundler (~> 1.0.0)
38
+ cassandra
39
+ jeweler (~> 1.5.1)
40
+ nokogiri
41
+ rcov
42
+ shoulda
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2009 Koziarski Software Ltd
2
+
3
+ Permission to use, copy, modify, and/or distribute this software for any
4
+ purpose with or without fee is hereby granted, provided that the above
5
+ copyright notice and this permission notice appear in all copies.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,79 @@
1
+ # Cassandra Object
2
+
3
+ Cassandra Object provides a nice API for working with [Cassandra](http://incubator.apache.org/cassandra/). CassandraObjects are mostly duck-type compatible with ActiveRecord objects so most of your controller code should work ok. Note that they're *mostly* compatible, Cassandra has no support for dynamic queries, or sorting. So the following kinds of operations aren't supported and *never will be*.
4
+
5
+ * `:order`
6
+ * `:conditions`
7
+ * `:joins`
8
+ * `:group`
9
+
10
+ There isn't much in the way of documentation yet, but a few examples.
11
+
12
+ class Customer < CassandraObject::Base
13
+ attribute :first_name, :type => :string
14
+ attribute :last_name, :type => :string
15
+ attribute :date_of_birth, :type => :date
16
+ attribute :signed_up_at, :type => :time_with_zone
17
+
18
+ validate :should_be_cool
19
+
20
+ key :uuid
21
+
22
+ index :date_of_birth
23
+
24
+ association :invoices, :unique=>false, :inverse_of=>:customer
25
+
26
+ private
27
+
28
+ def should_be_cool
29
+ unless ["Michael", "Anika", "Evan", "James"].include?(first_name)
30
+ errors.add(:first_name, "must be that of a cool person")
31
+ end
32
+ end
33
+ end
34
+
35
+ class Invoice < CassandraObject::Base
36
+ attribute :number, :type=>:integer
37
+ attribute :total, :type=>:float
38
+ attribute :gst_number, :type=>:string
39
+
40
+ # indexes can have a single entry also.
41
+ index :number, :unique=>true
42
+
43
+ # bi-directional associations with read-repair support.
44
+ association :customer, :unique=>true, :inverse_of=>:invoices
45
+
46
+ # Read migration support
47
+ migrate 1 do |attrs|
48
+ attrs["total"] ||= rand(2000) / 100.0
49
+ end
50
+
51
+ migrate 2 do |attrs|
52
+ attrs["gst_number"] = "66-666-666"
53
+ end
54
+
55
+ key :natural, :attributes => :number
56
+ end
57
+
58
+ @invoice = Invoice.get("12345")
59
+ @invoice.customer.invoices.all.include?(@invoice) # true
60
+
61
+ # FAQ
62
+
63
+ ## How do I make this work?
64
+
65
+ Here are some basic directions:
66
+
67
+ 1. `git clone git://github.com/NZKoz/cassandra_object.git`
68
+ 2. Run the bundler `gem bundle`
69
+ 3. Make sure the tests pass `rake test`
70
+
71
+ This gem has backwards compatibility with active support version 2.3.x, this is to enable people to use it with rails 2.3 applications. This backwards compatibility may not continue after the 1.0 release.
72
+
73
+ ## Should I use this in production?
74
+
75
+ Only if you're looking to help out with the development, there are a bunch of rough edges right now.
76
+
77
+ ## Why do you use a superclass and not a module.
78
+
79
+ Because.
data/Rakefile ADDED
@@ -0,0 +1,74 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'rake'
11
+
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gem|
14
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
+ gem.name = "gotime-cassandra_object"
16
+ gem.homepage = "http://github.com/gotime/cassandra_object"
17
+ gem.license = "MIT"
18
+ gem.summary = %Q{Cassandra ActiveModel}
19
+ gem.description = %Q{Cassandra ActiveModel}
20
+ gem.email = "grantr@gmail.com"
21
+ gem.authors = ["Michael Koziarski", "grantr"]
22
+ end
23
+ Jeweler::RubygemsDotOrgTasks.new
24
+
25
+ require 'rake/testtask'
26
+ Rake::TestTask.new(:test) do |test|
27
+ test.libs << 'lib' << 'test'
28
+ test.pattern = 'test/**/test_*.rb'
29
+ test.verbose = true
30
+ end
31
+
32
+ require 'rcov/rcovtask'
33
+ Rcov::RcovTask.new do |test|
34
+ test.libs << 'test'
35
+ test.pattern = 'test/**/test_*.rb'
36
+ test.verbose = true
37
+ end
38
+
39
+ task :default => :test
40
+
41
+ require 'rake/rdoctask'
42
+ Rake::RDocTask.new do |rdoc|
43
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
44
+
45
+ rdoc.rdoc_dir = 'rdoc'
46
+ rdoc.title = "cassandra_object #{version}"
47
+ rdoc.rdoc_files.include('README*')
48
+ rdoc.rdoc_files.include('lib/**/*.rb')
49
+ end
50
+
51
+ task :cleanup do
52
+ unless defined?(CassandraObject)
53
+ $: << 'test'
54
+ $: << 'lib'
55
+ require 'test_helper'
56
+ end
57
+ puts "Clearing keyspace! ..."
58
+ CassandraObject::Base.connection.clear_keyspace!
59
+ puts "Cleared"
60
+ end
61
+
62
+ task :config_snippet do
63
+ unless defined?(CassandraObject)
64
+ $: << 'test'
65
+ $: << 'lib'
66
+ require 'test_helper'
67
+ end
68
+
69
+ puts CassandraObject::Base.storage_config_xml
70
+ end
71
+
72
+ task :default=>[:test, :cleanup] do
73
+ end
74
+
data/TODO ADDED
@@ -0,0 +1,2 @@
1
+ * Support for alternate column names in associations and indexes
2
+ * Support for compound keys for associations e.g. "#{customer_id}:#{invoice_date}"
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.6.1
@@ -0,0 +1,134 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{gotime-cassandra_object}
8
+ s.version = "0.6.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Michael Koziarski", "grantr"]
12
+ s.date = %q{2010-12-10}
13
+ s.description = %q{Cassandra ActiveModel}
14
+ s.email = %q{grantr@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.markdown",
18
+ "TODO"
19
+ ]
20
+ s.files = [
21
+ "CHANGELOG",
22
+ "Gemfile",
23
+ "Gemfile.lock",
24
+ "LICENSE",
25
+ "README.markdown",
26
+ "Rakefile",
27
+ "TODO",
28
+ "VERSION",
29
+ "cassandra_object.gemspec",
30
+ "lib/cassandra_object.rb",
31
+ "lib/cassandra_object/associations.rb",
32
+ "lib/cassandra_object/associations/one_to_many.rb",
33
+ "lib/cassandra_object/associations/one_to_one.rb",
34
+ "lib/cassandra_object/attributes.rb",
35
+ "lib/cassandra_object/base.rb",
36
+ "lib/cassandra_object/callbacks.rb",
37
+ "lib/cassandra_object/collection.rb",
38
+ "lib/cassandra_object/cursor.rb",
39
+ "lib/cassandra_object/dirty.rb",
40
+ "lib/cassandra_object/identity.rb",
41
+ "lib/cassandra_object/identity/abstract_key_factory.rb",
42
+ "lib/cassandra_object/identity/key.rb",
43
+ "lib/cassandra_object/identity/natural_key_factory.rb",
44
+ "lib/cassandra_object/identity/uuid_key_factory.rb",
45
+ "lib/cassandra_object/indexes.rb",
46
+ "lib/cassandra_object/log_subscriber.rb",
47
+ "lib/cassandra_object/migrations.rb",
48
+ "lib/cassandra_object/mocking.rb",
49
+ "lib/cassandra_object/persistence.rb",
50
+ "lib/cassandra_object/serialization.rb",
51
+ "lib/cassandra_object/type_registration.rb",
52
+ "lib/cassandra_object/types.rb",
53
+ "lib/cassandra_object/validation.rb",
54
+ "test/basic_scenarios_test.rb",
55
+ "test/callbacks_test.rb",
56
+ "test/config/cassandra.in.sh",
57
+ "test/config/log4j.properties",
58
+ "test/config/storage-conf.xml",
59
+ "test/connection.rb",
60
+ "test/cursor_test.rb",
61
+ "test/dirty_test.rb",
62
+ "test/fixture_models.rb",
63
+ "test/identity/natural_key_factory_test.rb",
64
+ "test/index_test.rb",
65
+ "test/legacy/test_helper.rb",
66
+ "test/migration_test.rb",
67
+ "test/one_to_many_associations_test.rb",
68
+ "test/test_case.rb",
69
+ "test/test_helper.rb",
70
+ "test/time_test.rb",
71
+ "test/types_test.rb",
72
+ "test/validation_test.rb",
73
+ "test/z_mock_test.rb"
74
+ ]
75
+ s.homepage = %q{http://github.com/gotime/cassandra_object}
76
+ s.licenses = ["MIT"]
77
+ s.require_paths = ["lib"]
78
+ s.rubygems_version = %q{1.3.7}
79
+ s.summary = %q{Cassandra ActiveModel}
80
+ s.test_files = [
81
+ "test/basic_scenarios_test.rb",
82
+ "test/callbacks_test.rb",
83
+ "test/connection.rb",
84
+ "test/cursor_test.rb",
85
+ "test/dirty_test.rb",
86
+ "test/fixture_models.rb",
87
+ "test/identity/natural_key_factory_test.rb",
88
+ "test/index_test.rb",
89
+ "test/legacy/test_helper.rb",
90
+ "test/migration_test.rb",
91
+ "test/one_to_many_associations_test.rb",
92
+ "test/test_case.rb",
93
+ "test/test_helper.rb",
94
+ "test/time_test.rb",
95
+ "test/types_test.rb",
96
+ "test/validation_test.rb",
97
+ "test/z_mock_test.rb"
98
+ ]
99
+
100
+ if s.respond_to? :specification_version then
101
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
102
+ s.specification_version = 3
103
+
104
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
105
+ s.add_runtime_dependency(%q<activesupport>, ["~> 3"])
106
+ s.add_runtime_dependency(%q<activemodel>, ["~> 3"])
107
+ s.add_runtime_dependency(%q<cassandra>, [">= 0"])
108
+ s.add_runtime_dependency(%q<nokogiri>, [">= 0"])
109
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
110
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
111
+ s.add_development_dependency(%q<jeweler>, ["~> 1.5.1"])
112
+ s.add_development_dependency(%q<rcov>, [">= 0"])
113
+ else
114
+ s.add_dependency(%q<activesupport>, ["~> 3"])
115
+ s.add_dependency(%q<activemodel>, ["~> 3"])
116
+ s.add_dependency(%q<cassandra>, [">= 0"])
117
+ s.add_dependency(%q<nokogiri>, [">= 0"])
118
+ s.add_dependency(%q<shoulda>, [">= 0"])
119
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
120
+ s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
121
+ s.add_dependency(%q<rcov>, [">= 0"])
122
+ end
123
+ else
124
+ s.add_dependency(%q<activesupport>, ["~> 3"])
125
+ s.add_dependency(%q<activemodel>, ["~> 3"])
126
+ s.add_dependency(%q<cassandra>, [">= 0"])
127
+ s.add_dependency(%q<nokogiri>, [">= 0"])
128
+ s.add_dependency(%q<shoulda>, [">= 0"])
129
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
130
+ s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
131
+ s.add_dependency(%q<rcov>, [">= 0"])
132
+ end
133
+ end
134
+
@@ -0,0 +1,13 @@
1
+ require 'rubygems'
2
+ require 'i18n'
3
+ require 'active_support'
4
+
5
+ module CassandraObject
6
+ VERSION = "0.5.0"
7
+ end
8
+
9
+
10
+ require 'active_support/all'
11
+ require 'active_model'
12
+
13
+ require 'cassandra_object/base'
@@ -0,0 +1,35 @@
1
+ require 'cassandra_object/associations/one_to_many'
2
+ require 'cassandra_object/associations/one_to_one'
3
+
4
+ module CassandraObject
5
+ module Associations
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ class_inheritable_hash :associations
10
+ end
11
+
12
+ module ClassMethods
13
+ def column_family_configuration
14
+ super << {:Name=>"#{name}Relationships", :CompareWith=>"UTF8Type", :CompareSubcolumnsWith=>"TimeUUIDType", :ColumnType=>"Super"}
15
+ end
16
+
17
+ def association(association_name, options= {})
18
+ if options[:unique]
19
+ write_inheritable_hash(:associations, {association_name => OneToOneAssociation.new(association_name, self, options)})
20
+ else
21
+ write_inheritable_hash(:associations, {association_name => OneToManyAssociation.new(association_name, self, options)})
22
+ end
23
+ end
24
+
25
+ def remove(key)
26
+ begin
27
+ connection.remove("#{name}Relationships", key.to_s)
28
+ rescue Cassandra::AccessError => e
29
+ raise e unless e.message =~ /Invalid column family/
30
+ end
31
+ super
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,136 @@
1
+ module CassandraObject
2
+ class OneToManyAssociation
3
+ def initialize(association_name, owner_class, options)
4
+ @association_name = association_name.to_s
5
+ @owner_class = owner_class
6
+ @target_class_name = options[:class_name] || association_name.to_s.singularize.camelize
7
+ @options = options
8
+
9
+ define_methods!
10
+ end
11
+
12
+ def find(owner, options = {})
13
+ reversed = options.has_key?(:reversed) ? options[:reversed] : reversed?
14
+ cursor = CassandraObject::Cursor.new(target_class, column_family, owner.key.to_s, @association_name, :start_after => options[:start_after], :reversed => reversed)
15
+ cursor.find(options[:limit] || 100)
16
+ end
17
+
18
+ def add(owner, record, set_inverse = true)
19
+ connection.insert(column_family, owner.key.to_s, {@association_name=>{new_key=>record.key.to_s}})
20
+ if has_inverse? && set_inverse
21
+ inverse.set_inverse(record, owner)
22
+ end
23
+ end
24
+
25
+ def new_key
26
+ SimpleUUID::UUID.new
27
+ end
28
+
29
+ def column_family
30
+ @owner_class.to_s + "Relationships"
31
+ end
32
+
33
+ def connection
34
+ @owner_class.connection
35
+ end
36
+
37
+ def target_class
38
+ @target_class ||= @target_class_name.constantize
39
+ end
40
+
41
+ def new_proxy(owner)
42
+ OneToManyAssociationProxy.new(self, owner)
43
+ end
44
+
45
+ def has_inverse?
46
+ @options[:inverse_of]
47
+ end
48
+
49
+ def inverse
50
+ has_inverse? && target_class.associations[@options[:inverse_of]]
51
+ end
52
+
53
+ def set_inverse(owner, record)
54
+ add(owner, record, false)
55
+ end
56
+
57
+ def reversed?
58
+ @options[:reversed] == true
59
+ end
60
+
61
+ def define_methods!
62
+ @owner_class.class_eval <<-eos
63
+ def #{@association_name}
64
+ @_#{@association_name} ||= self.class.associations[:#{@association_name}].new_proxy(self)
65
+ end
66
+ eos
67
+ end
68
+ end
69
+
70
+ class OneToManyAssociationProxy
71
+ def initialize(association, owner)
72
+ @association = association
73
+ @owner = owner
74
+ end
75
+
76
+ include Enumerable
77
+ def each
78
+ target.each do |i|
79
+ yield i
80
+ end
81
+ end
82
+
83
+ def <<(record)
84
+ @association.add(@owner, record)
85
+ if loaded?
86
+ @target << record
87
+ end
88
+ end
89
+
90
+ # Get the targets of this association proxy
91
+ #
92
+ # @param [Hash] options the options with which to modify this query
93
+ # @option options [String] :start_after the key after which to start returning results
94
+ # @option options [Boolean] :reversed (false or association default) return the results in reverse order
95
+ # @option options [Integer] :limit the max number of results to return
96
+ # @return [Array<CassandraObject::Base>] an array of objects of type self#target_class
97
+ #
98
+ def all(options = {})
99
+ @association.find(@owner, options)
100
+ end
101
+
102
+ # Create a record of the associated type with
103
+ # the supplied attributes and add it to this
104
+ # association
105
+ #
106
+ # @param [Hash] attributes the attributes with which to create the object
107
+ # @return [CassandraObject::Base] the newly created object
108
+ #
109
+ def create(attributes)
110
+ @association.target_class.create(attributes).tap do |record|
111
+ if record.valid?
112
+ self << record
113
+ end
114
+ end
115
+ end
116
+
117
+ def create!(attributes)
118
+ @association.target_class.create!(attributes).tap do |record|
119
+ self << record
120
+ end
121
+ end
122
+
123
+ def target
124
+ @target ||= begin
125
+ @loaded = true
126
+ @association.find(@owner)
127
+ end
128
+ end
129
+
130
+ alias to_a target
131
+
132
+ def loaded?
133
+ defined?(@loaded) && @loaded
134
+ end
135
+ end
136
+ end