zentradi 0.0.0 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -61,7 +61,7 @@ In particular, I want:
61
61
  [
62
62
  "magic",
63
63
  "ruby hooks overrides",
64
- "additions to the mongo mapper API",
64
+ "additions to the mongo driver API",
65
65
  "plugins paraphernalia",
66
66
  "use and abuse of generated methods -- find_by_blah_blah anyone? -- ",
67
67
  "features of ActiveRecord, Datamapper, [INSERT ORM HERE]"
data/Rakefile CHANGED
@@ -22,7 +22,6 @@ begin
22
22
  gem.add_development_dependency "rake"
23
23
  gem.add_dependency "mongo"
24
24
  gem.add_dependency "mongo_ext"
25
- gem.add_dependency "weak_hash"
26
25
  gem.add_dependency "hashie"
27
26
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
28
27
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.0
1
+ 0.0.1
data/lib/zentradi.rb CHANGED
@@ -1,13 +1,18 @@
1
1
  require 'hashie'
2
- require 'weak_hash'
3
2
  require 'mongo'
4
3
 
5
- module Zentradi
6
- autoload :Utils, "zentradi/utils"
7
- autoload :ClassHelpers, 'zentradi/class_helpers'
8
- autoload :Instantiators, 'zentradi/instantiators'
9
- autoload :IdentityMap, 'zentradi/identity_map'
10
- autoload :Connection, 'zentradi/connection'
11
- autoload :Finders, 'zentradi/finders'
12
- autoload :Document, 'zentradi/document'
4
+ module Zdi
5
+ autoload :Delegate , 'zentradi/delegate'
6
+ autoload :DocumentWrapper , 'zentradi/document_wrapper'
7
+ autoload :Collection , 'zentradi/collection'
8
+
9
+ class << self
10
+ attr_accessor :default_database
11
+
12
+ def Collection(collection, database = Zdi.default_database)
13
+ Class.new(Zdi::Collection) do
14
+ instance_variable_set("@collection", database[collection])
15
+ end
16
+ end
17
+ end
13
18
  end
@@ -0,0 +1,56 @@
1
+ module Zdi
2
+ class Collection
3
+ class << self
4
+ extend Zdi::Delegate
5
+ delegate *(Mongo::Collection.public_instance_methods - public_instance_methods), :to => :collection
6
+ end
7
+
8
+ module ClassMethods
9
+ attr_accessor :collection
10
+
11
+ def inherited(base)
12
+ base.collection = self.collection
13
+ end
14
+
15
+ def ensure_collection
16
+ database.create_collection(collection.name)
17
+ end
18
+
19
+ def drop_collection
20
+ collection.drop
21
+ end
22
+
23
+ def recreate_collection
24
+ drop_collection; ensure_collection
25
+ end
26
+
27
+ def build(attributes = {})
28
+ DocumentWrapper.new(self, attributes)
29
+ end
30
+
31
+ def create(attributes = {})
32
+ doc = build(attributes)
33
+ doc.save
34
+ doc
35
+ end
36
+
37
+ def find_or_build(attributes)
38
+ find_one(attributes) || build(attributes)
39
+ end
40
+
41
+ def find_or_create(attributes)
42
+ update(attributes, attributes, :upsert => true)
43
+ end
44
+
45
+ def all
46
+ find
47
+ end
48
+ end
49
+
50
+ extend ClassMethods
51
+
52
+ class << self
53
+ alias_method :first, :find_one
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,32 @@
1
+ module Zdi
2
+ module Delegate
3
+ def delegate(*methods)
4
+ include Wrapper unless ancestors.include?(Wrapper)
5
+ to = methods.pop[:to]
6
+ methods.each do |name|
7
+ module_eval(<<-EOMETHOD, __FILE__, __LINE__ + 1)
8
+ def #{ name }(*args, &block)
9
+ new_args = args.map { |a| a.is_a?(DocumentWrapper) ? a.to_hash : a }
10
+
11
+ result = #{to}.send :#{name}, *new_args, &block
12
+
13
+ return wrap_if_document(result)
14
+ end
15
+ EOMETHOD
16
+ end
17
+ end
18
+
19
+ module Wrapper
20
+ def wrap_if_document(object)
21
+ if object.is_a?(OrderedHash)
22
+ DocumentWrapper.new(self, object)
23
+ elsif object.respond_to?(:map)
24
+ object.map { |e| wrap_if_document(e) }
25
+ else
26
+ return object
27
+ end
28
+ end
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,38 @@
1
+ module Zdi
2
+ class DocumentWrapper < Hashie::Mash
3
+
4
+ attr_reader :collection
5
+
6
+ def initialize(collection, hash = {})
7
+ super(hash)
8
+ @collection = collection
9
+ end
10
+
11
+ def id
12
+ super || _id
13
+ end
14
+
15
+ def new?
16
+ id.nil? || @collection.find("_id" => id).count == 0
17
+ end
18
+
19
+ def save
20
+ if id.nil?
21
+ self.id = @collection.save(self)
22
+ else
23
+ @collection.update({"_id" => id}, self)
24
+ end
25
+ self
26
+ end
27
+
28
+ def update(attributes)
29
+ super(attributes)
30
+ save
31
+ end
32
+
33
+ def destroy
34
+ @collection.remove("_id" => id)
35
+ end
36
+
37
+ end
38
+ end
data/spec/spec_helper.rb CHANGED
@@ -1 +1,3 @@
1
1
  require 'zentradi'
2
+
3
+ Zdi.default_database = Mongo::Connection.new.db("zentradi")
@@ -1,19 +1,14 @@
1
1
  require 'spec_helper'
2
2
 
3
- class Post < Zentradi::Document
4
- mongo :collection => "post", :database => "zentradi"
3
+ Post = Zdi::Collection("posts")
5
4
 
6
- mongo_accessor :title
7
- end
8
-
9
- describe Zentradi::Document do
5
+ describe Zdi::Collection do
10
6
  before do
11
7
  Post.remove
12
8
  end
13
9
 
14
10
  it "creates a document" do
15
- post = Post.new
16
- post.id.should be_nil
11
+ post = Post.build
17
12
  post.should be_new
18
13
 
19
14
  post.save
@@ -22,18 +17,14 @@ describe Zentradi::Document do
22
17
  post.should_not be_new
23
18
  end
24
19
 
25
- it "finds a document through the identity map" do
26
- @post = Post.create(:title => "Hola Mundo", :body => "Hi.")
27
- Post.first("_id" => @post.id).should be_an_instance_of(Post)
28
- end
29
20
 
30
21
  it "finds or initializes a document" do
31
22
  @post = Post.create(:title => "Test")
32
23
 
33
- found = Post.find_or_initialize(:title => "Test")
24
+ found = Post.find_or_build(:title => "Test")
34
25
  found.title.should == "Test"
35
26
 
36
- found = Post.find_or_initialize(:title => "Test 2")
27
+ found = Post.find_or_build(:title => "Test 2")
37
28
  found.title.should == "Test 2"
38
29
  found.should be_new
39
30
  found.save
@@ -43,11 +34,14 @@ describe Zentradi::Document do
43
34
  end
44
35
 
45
36
  it "updates a document" do
46
- @post = Post.create(:title => "Hola Mundo", :body => "Hi.")
47
- @post.title = "ABC"
48
- @post.save
49
- @post.reload
50
- @post.title.should == "ABC"
37
+ post = Post.create(:title => "Hola Mundo", :body => "Hi.")
38
+ post.title = "ABC"
39
+ post.save
40
+
41
+ post.update(:title => post.title + " DEF")
42
+
43
+ from_db = Post.first("_id" => post.id)
44
+ from_db.title.should == "ABC DEF"
51
45
  end
52
46
 
53
47
  it "destroys a document" do
@@ -1,3 +1,4 @@
1
+ __END__
1
2
  require 'spec_helper'
2
3
 
3
4
  class Book < Zentradi::Document
data/zentradi.gemspec ADDED
@@ -0,0 +1,72 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{zentradi}
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Emmanuel Oga"]
12
+ s.date = %q{2010-03-29}
13
+ s.description = %q{minimalistic tools for accessing mongodb}
14
+ s.email = %q{EmmanuelOga@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "Gemfile",
23
+ "LICENSE",
24
+ "README.rdoc",
25
+ "Rakefile",
26
+ "VERSION",
27
+ "lib/zentradi.rb",
28
+ "lib/zentradi/collection.rb",
29
+ "lib/zentradi/delegate.rb",
30
+ "lib/zentradi/document_wrapper.rb",
31
+ "spec/spec_helper.rb",
32
+ "spec/zentradi/document_spec.rb",
33
+ "spec/zentradi/indexes_spec.rb",
34
+ "zentradi.gemspec"
35
+ ]
36
+ s.homepage = %q{http://github.com/EmmanuelOga/zentradi}
37
+ s.rdoc_options = ["--charset=UTF-8"]
38
+ s.require_paths = ["lib"]
39
+ s.rubygems_version = %q{1.3.6}
40
+ s.summary = %q{minimalistic tools for accessing mongodb}
41
+ s.test_files = [
42
+ "spec/zentradi/document_spec.rb",
43
+ "spec/zentradi/indexes_spec.rb",
44
+ "spec/spec_helper.rb"
45
+ ]
46
+
47
+ if s.respond_to? :specification_version then
48
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
49
+ s.specification_version = 3
50
+
51
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
52
+ s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
53
+ s.add_development_dependency(%q<rake>, [">= 0"])
54
+ s.add_runtime_dependency(%q<mongo>, [">= 0"])
55
+ s.add_runtime_dependency(%q<mongo_ext>, [">= 0"])
56
+ s.add_runtime_dependency(%q<hashie>, [">= 0"])
57
+ else
58
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
59
+ s.add_dependency(%q<rake>, [">= 0"])
60
+ s.add_dependency(%q<mongo>, [">= 0"])
61
+ s.add_dependency(%q<mongo_ext>, [">= 0"])
62
+ s.add_dependency(%q<hashie>, [">= 0"])
63
+ end
64
+ else
65
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
66
+ s.add_dependency(%q<rake>, [">= 0"])
67
+ s.add_dependency(%q<mongo>, [">= 0"])
68
+ s.add_dependency(%q<mongo_ext>, [">= 0"])
69
+ s.add_dependency(%q<hashie>, [">= 0"])
70
+ end
71
+ end
72
+
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 0
9
- version: 0.0.0
8
+ - 1
9
+ version: 0.0.1
10
10
  platform: ruby
11
11
  authors:
12
12
  - Emmanuel Oga
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-03-16 00:00:00 -03:00
17
+ date: 2010-03-29 00:00:00 -03:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -68,7 +68,7 @@ dependencies:
68
68
  type: :runtime
69
69
  version_requirements: *id004
70
70
  - !ruby/object:Gem::Dependency
71
- name: weak_hash
71
+ name: hashie
72
72
  prerelease: false
73
73
  requirement: &id005 !ruby/object:Gem::Requirement
74
74
  requirements:
@@ -79,18 +79,6 @@ dependencies:
79
79
  version: "0"
80
80
  type: :runtime
81
81
  version_requirements: *id005
82
- - !ruby/object:Gem::Dependency
83
- name: hashie
84
- prerelease: false
85
- requirement: &id006 !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- segments:
90
- - 0
91
- version: "0"
92
- type: :runtime
93
- version_requirements: *id006
94
82
  description: minimalistic tools for accessing mongodb
95
83
  email: EmmanuelOga@gmail.com
96
84
  executables: []
@@ -109,16 +97,13 @@ files:
109
97
  - Rakefile
110
98
  - VERSION
111
99
  - lib/zentradi.rb
112
- - lib/zentradi/class_helpers.rb
113
- - lib/zentradi/connection.rb
114
- - lib/zentradi/document.rb
115
- - lib/zentradi/identity_map.rb
116
- - lib/zentradi/instantiators.rb
100
+ - lib/zentradi/collection.rb
101
+ - lib/zentradi/delegate.rb
102
+ - lib/zentradi/document_wrapper.rb
117
103
  - spec/spec_helper.rb
118
104
  - spec/zentradi/document_spec.rb
119
- - spec/zentradi/identity_map_spec.rb
120
105
  - spec/zentradi/indexes_spec.rb
121
- - spec/zentradi_spec.rb
106
+ - zentradi.gemspec
122
107
  has_rdoc: true
123
108
  homepage: http://github.com/EmmanuelOga/zentradi
124
109
  licenses: []
@@ -150,8 +135,6 @@ signing_key:
150
135
  specification_version: 3
151
136
  summary: minimalistic tools for accessing mongodb
152
137
  test_files:
153
- - spec/zentradi_spec.rb
154
138
  - spec/zentradi/document_spec.rb
155
- - spec/zentradi/identity_map_spec.rb
156
139
  - spec/zentradi/indexes_spec.rb
157
140
  - spec/spec_helper.rb
@@ -1,46 +0,0 @@
1
- module Zentradi
2
- # Some random helpers to be used at class level.
3
- module ClassHelpers
4
-
5
- def instance_access_to_class_methods(*names)
6
- names.each do |name|
7
- module_eval(<<-EOMETHOD, __FILE__, __LINE__ + 1)
8
- def #{ name }(*args, &block)
9
- self.class.#{ name }(*args, &block)
10
- end
11
- EOMETHOD
12
- end
13
- end
14
-
15
- # creates a shortcut for accessing keys
16
- # on the mongo document.
17
- # Not really needed but seems like after
18
- # ActiveRecord nobody can live without this
19
- # (including me? :-)
20
- def mongo_accessor(*keys)
21
- keys.each do |key|
22
- module_eval(<<-EOMETHOD, __FILE__, __LINE__ + 1)
23
- def #{ key }
24
- document[#{key.inspect}]
25
- end
26
-
27
- def #{ key }=(val)
28
- document[#{key.inspect}] = val
29
- end
30
- EOMETHOD
31
- end
32
- end
33
-
34
- def delegate(*methods)
35
- to = methods.pop[:to]
36
- methods.each do |name|
37
- module_eval(<<-EOMETHOD, __FILE__, __LINE__ + 1)
38
- def #{ name }(*args, &block)
39
- #{to}.#{name}(*args, &block)
40
- end
41
- EOMETHOD
42
- end
43
- end
44
-
45
- end
46
- end
@@ -1,48 +0,0 @@
1
- module Zentradi
2
- # methods to manage the mongo driver communication artefacts
3
- module Connection
4
-
5
- def connection(*args)
6
- @_connection = nil unless args.empty?
7
- @_connection ||= Mongo::Connection.new(*args)
8
- end
9
-
10
- def database(database_name = nil)
11
- @_database = nil unless database_name.nil?
12
- @_database ||= connection.db(database_name)
13
- end
14
-
15
- def collection(collection_name = nil)
16
- @_collection = nil unless collection_name.nil?
17
- @_collection ||= database[collection_name]
18
- end
19
-
20
- # configuration shortcut
21
- def mongo(options)
22
- connection *options[:connection] if options.member?(:connection)
23
- database options[:database] if options.member?(:database)
24
- collection options[:collection] if options.member?(:collection)
25
- end
26
-
27
- # -------------------------------------------------------------------------
28
-
29
- def ensure_collection
30
- database.create_collection(collection.name)
31
- end
32
-
33
- def drop_collection!
34
- collection.drop
35
- end
36
-
37
- def recreate_collection!
38
- drop_collection! and ensure_collection
39
- end
40
-
41
- def identity_map
42
- raise RuntimeError, "please set the mongo database first" unless database
43
- raise RuntimeError, "please set the mongo collection first" unless collection
44
- Zentradi::IdentityMap[database.name, collection.name]
45
- end
46
-
47
- end
48
- end
@@ -1,83 +0,0 @@
1
- module Zentradi
2
- class Document
3
-
4
- extend Connection
5
- extend ClassHelpers
6
- extend Instantiators
7
-
8
- attr_accessor :document
9
- instance_access_to_class_methods :identity_map, :collection
10
-
11
- def initialize(document = nil)
12
- raise ArgumentError, "provide a Hash like object or no parameters" unless document.nil? || document.class.ancestors.include?(Hash)
13
-
14
- @document = document ? Hashie::Mash.new(document) : Hashie::Mash.new
15
- end
16
-
17
- def update(document)
18
- @document.update(document) and save
19
- end
20
-
21
- def update!(document)
22
- @document.update(document) and save!
23
- end
24
-
25
- def [](key)
26
- @document[key]
27
- end
28
-
29
- def []=(key, value)
30
- @document[key] = value
31
- end
32
-
33
- def id
34
- @document["_id"]
35
- end
36
-
37
- def new?
38
- not saved?
39
- end
40
-
41
- def saved?
42
- id && collection.find("_id" => id).count != 0
43
- end
44
-
45
- def save(safe = false)
46
- if id
47
- collection.update({"_id" => id}, @document, :safe => safe)
48
- else
49
- update("_id" => collection.save(@document, :safe => safe))
50
- end
51
- end
52
-
53
- def save!
54
- save(true)
55
- end
56
-
57
- def destroy
58
- if id
59
- collection.remove("_id" => id)
60
- @document.delete("_id")
61
- end
62
- end
63
-
64
- def reload
65
- if _id = id
66
- @document.clear["_id"] = _id # clear and set.
67
- update(mongo_document)
68
- end
69
-
70
- self
71
- end
72
-
73
- private
74
- def mongo_document
75
- raise RuntimeError, "cannot retrieve a new document" if new?
76
-
77
- collection.find_one("_id" => id).tap do |i|
78
- raise RuntimeError, "nothing was retrieved while loading the mongo instance ( #{ i.inspect } )" if i.nil? || i.empty?
79
- end
80
- end
81
-
82
- end
83
- end
@@ -1,75 +0,0 @@
1
- module Zentradi
2
- # NOTE: WIP, not working yet.
3
- #
4
- # Stores weak references to objects to ensure only one
5
- # instance of a ruby class is used for holding a reference
6
- # to a specific mongo collection.
7
- class IdentityMap
8
- class << self
9
- # one identity map per db/collection tuple
10
- def [](db_name, collection_name)
11
- @hash ||= Hash.new { |h,k| h[k] = Hash.new { |hh, kk| hh[kk] = IdentityMap.new } }
12
- @hash[db_name][collection_name]
13
- end
14
- end
15
-
16
- def initialize
17
- @map = WeakHash.new
18
- end
19
-
20
- # retrieves a document with given _id
21
- def get(_id)
22
- @map[_id].tap { |instance| check(_id, instance) }
23
- end
24
-
25
- # stores a reference to the mongo document.
26
- def set(_id, instance)
27
- check(_id, @map[_id] = instance)
28
- end
29
-
30
- private
31
- def check(_id, instance)
32
- raise ArgumentError, "instance must be a Zentradi::Document" unless instance.nil? || instance.is_a?(Zentradi::Document)
33
- raise RuntimeError, "instance #{ instance.inspect } does not match _id: #{ _id }" if instance && ( instance.id != _id )
34
- instance
35
- end
36
-
37
- # Some helper methods to enable / disable the identity map at a class level.
38
- module Management
39
- def enable_identity_map
40
- @_identity_map = true
41
- end
42
-
43
- def disable_identity_map
44
- @_identity_map = false
45
- end
46
-
47
- # enabled by default
48
- def identity_map_enabled?
49
- @_identity_map.nil? || @_identity_map
50
- end
51
-
52
- private
53
-
54
- def fetch_instance(param_doc)
55
- if param_doc.nil?
56
- nil
57
- elsif identity_map_enabled? && param_doc["_id"]
58
-
59
- if instance = identity_map.get(param_doc["_id"])
60
- instance.update(param_doc)
61
- else
62
- document = param_doc.is_a?(Document) ? param_doc : new(param_doc)
63
- instance = identity_map.set(document["_id"], document)
64
- end
65
-
66
- instance
67
- else
68
- param_doc.is_a?(Document) ? param_doc : new(param_doc)
69
- end
70
- end
71
-
72
- end # end module Management
73
-
74
- end
75
- end
@@ -1,36 +0,0 @@
1
- module Zentradi
2
- module Instantiators
3
- extend ClassHelpers
4
-
5
- delegate :remove, :update, :to => :collection
6
-
7
- def all(params = nil)
8
- collection.find(params).map(&method(:instantiate))
9
- end
10
-
11
- def first(params = nil)
12
- query = params.is_a?(String) || params.is_a?(Numeric) ? {"_id" => params} : params
13
-
14
- instantiate collection.find_one(query)
15
- end
16
-
17
- def find_or_initialize(params)
18
- raise RuntimeError, "cannot find a document without params" if params.nil?
19
-
20
- first(params) || instantiate(params)
21
- end
22
-
23
- def create(params)
24
- instantiate(params).tap { |n| n.save }
25
- end
26
-
27
- def create!(params)
28
- instantiate(params).tap { |n| n.save! }
29
- end
30
-
31
- def instantiate(document)
32
- document ? new(document) : nil
33
- end
34
-
35
- end
36
- end
@@ -1,26 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Zentradi::IdentityMap do
4
- before do
5
- @oh = Zentradi::Document.new
6
- @oh["_id"] = "123456"
7
-
8
- @im = Zentradi::IdentityMap["a_db", "a_collection"]
9
-
10
- GC.start # make sure @im is collected if it was overwritten (e.g. in second example run)
11
- end
12
-
13
- it "stores an object" do
14
- @im.set("123456", @oh)
15
- @im.get("123456").should == @oh
16
- end
17
-
18
- it "stores a weak reference" do
19
- @im.set("123456", @oh)
20
- @im.get("123456").should == @oh
21
-
22
- @oh = nil; GC.start
23
-
24
- @im.get("123456").should be_nil
25
- end
26
- end
@@ -1,7 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Zentradi do
4
- it "works" do
5
- true.should be_true
6
- end
7
- end