hollybush 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ ruby-1.9.2-p180/
6
+ .DS_Store
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm 1.9.2@hollybush
@@ -0,0 +1,4 @@
1
+ # Hollybush Changelog
2
+
3
+ ## 0.0.1 - Initialise providing basic features such as List and Entry management.
4
+ ## 0.0.2 - Bug fixes, support for MongoHQ datasource URLs and sharing of an external MongDB database object.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in hollybush.gemspec
4
+ gemspec
@@ -0,0 +1,18 @@
1
+ # Hollybush
2
+
3
+ Hollybush is a gem to manage flexible structured lists, using MongoDB as a backing database. Hollybush is
4
+ intended to be used in a variety of scenarios including outlining tools and todo list managers.
5
+
6
+ WARNING: This gem is currently under heavy development and subject to a shedload of change. You're best not using it.
7
+
8
+ ## Copyright
9
+
10
+ (The MIT License)
11
+
12
+ Copyright © 2010 Ijonas Kisselbach
13
+
14
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
15
+
16
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
17
+
18
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,4 @@
1
+ require "rubygems"
2
+ require "bundler/setup"
3
+
4
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,32 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "hollybush/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "hollybush"
7
+ s.version = Hollybush::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Ijonas Kisselbach"]
10
+ s.email = ["ijonas.kisselbach@gmail.com"]
11
+ s.homepage = "http://github.com/ijonas/hollybush"
12
+ s.summary = %q{Flexible structured list manager backed by MongoDB.}
13
+ s.description = %q{Light-weight flexible structured list implementation.}
14
+
15
+ s.rubyforge_project = "hollybush"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_dependency "mongo"
23
+ s.add_dependency "mongo_ext"
24
+ s.add_dependency "bson"
25
+ s.add_dependency "bson_ext"
26
+ s.add_dependency "activemodel"
27
+ s.add_dependency "activesupport"
28
+
29
+ s.add_development_dependency "rspec"
30
+ s.add_development_dependency "awesome_print"
31
+
32
+ end
@@ -0,0 +1,10 @@
1
+ require "rubygems"
2
+ require "bundler/setup"
3
+
4
+ require "mongo"
5
+ require "active_model"
6
+ require "active_support"
7
+ require "logger"
8
+
9
+ require File.expand_path(File.join(File.dirname(__FILE__), '/hollybush/connectivity'))
10
+ require File.expand_path(File.join(File.dirname(__FILE__), '/hollybush/list'))
@@ -0,0 +1,23 @@
1
+ module Hollybush
2
+ unless defined?(@@mongodb) and @@mongodb
3
+ if ENV['MONGOHQ_URL']
4
+ log = Logger.new(STDOUT)
5
+ log.level = Logger::DEBUG
6
+
7
+ uri = URI.parse(ENV['MONGOHQ_URL'])
8
+ conn = Mongo::Connection.new(uri.host, uri.port)
9
+ @@mongodb = conn.db(uri.path.gsub(/^\//, ''))
10
+ @@mongodb.authenticate(uri.user, uri.password) unless uri.user.nil? or uri.user.empty?
11
+ end
12
+ end
13
+ def self.mongodb=(mongodb)
14
+ @@mongodb = mongodb
15
+ end
16
+ def self.mongodb
17
+ unless defined?(@@mongodb) and @@mongodb
18
+ puts "PLEASE SPECIFY A MONGODB DATABASE OBJECT. Use Hollybush.mongodb="
19
+ return nil
20
+ end
21
+ @@mongodb
22
+ end
23
+ end
@@ -0,0 +1,136 @@
1
+ module Hollybush
2
+
3
+ class List
4
+ include Enumerable
5
+ include ActiveModel::Validations
6
+ include ActiveModel::Conversion
7
+ extend ActiveModel::Naming
8
+
9
+ attr_accessor :id, :name, :entries
10
+ validates_presence_of :name
11
+
12
+ def initialize(attributes = {})
13
+ update_attributes(attributes)
14
+ @entries = [] unless @entries
15
+ @id = attributes["_id"].to_s if attributes.include?("_id")
16
+ end
17
+
18
+ def save
19
+ if valid?
20
+ update_doc = {:name => @name, :entries => @entries}
21
+ if @id
22
+ List.coll.update({"_id" => make_id(@id)}, update_doc)
23
+ else
24
+ @id = List.coll.save(update_doc).to_s
25
+ end
26
+ else
27
+ false
28
+ end
29
+ end
30
+
31
+ def self.create(attributes)
32
+ list = List.new(attributes)
33
+ list.save
34
+ list
35
+ end
36
+
37
+ def each(&a_block)
38
+ doc = List.coll.find_one({"_id" => @id})
39
+ doc["entries"].each(&a_block) if doc["entries"]
40
+ end
41
+
42
+ def <<(entry)
43
+ save unless persisted?
44
+ BSON::ObjectId.create_pk(entry)
45
+ @entries << entry if List.coll.update({"_id" => make_id(@id)}, {"$push" => {:entries => entry}})
46
+ end
47
+
48
+ def delete_entry(entry)
49
+ @entries.delete(entry) if List.coll.update({"_id" => make_id(@id)}, {"$pull" => {:entries => {"_id" => entry["_id"]}}})
50
+ end
51
+
52
+ def update_entry(entry)
53
+ entry["_id"] = make_id(entry["_id"])
54
+ List.coll.update({"_id" => make_id(@id), "entries._id" => entry["_id"]}, {"$set" => {"entries.$"=> entry}})
55
+ end
56
+
57
+ def persisted?
58
+ @id != nil
59
+ end
60
+
61
+ def update_attributes(attributes = {})
62
+ attributes.each do |name, value|
63
+ send("#{name}=", value) if respond_to?(name)
64
+ end
65
+ end
66
+
67
+ def delete
68
+ List.coll.remove({"_id" => make_id(@id)})
69
+ end
70
+
71
+ def self.delete(query = {})
72
+ begin
73
+ List.coll.remove(prepare(query))
74
+ rescue BSON::InvalidObjectId
75
+ end
76
+ end
77
+
78
+ def self.delete_entry(query = {})
79
+ begin
80
+ List.coll.remove(prepare(query))
81
+ rescue BSON::InvalidObjectId
82
+ end
83
+ end
84
+
85
+
86
+ def self.find(query = {}, options = {})
87
+ begin
88
+ coll.find(prepare(query), options).to_a.map {|doc| Hollybush::List.new(doc)}
89
+ rescue BSON::InvalidObjectId => e
90
+ puts e.message
91
+ []
92
+ end
93
+ end
94
+
95
+ def self.count(query = {})
96
+ coll.find(query, :fields => []).count
97
+ end
98
+
99
+ private
100
+ def make_id(id)
101
+ BSON::ObjectId.from_string(id)
102
+ end
103
+
104
+ def make_random_id
105
+ BSON::ObjectId.from_string(id)
106
+ end
107
+
108
+ def self.coll
109
+ begin
110
+ Hollybush.mongodb.collection(:list)
111
+ rescue Exception => e
112
+ puts e.message
113
+ puts e.backtrace.join("\n")
114
+ end
115
+ end
116
+
117
+ def self.prepare(query)
118
+ ids = ["id", "_id", :id, :_id]
119
+ new_bson_id = nil
120
+ # we support querying by various incarnations of 'id' when in actual fact the query should be on '_id', so lets correct that
121
+ ids.map do |id_key|
122
+ if query.include?(id_key)
123
+ new_bson_id = BSON::ObjectId.from_string(query[id_key])
124
+ query.delete id_key
125
+ end
126
+ end
127
+ query["_id"] = new_bson_id if new_bson_id
128
+ query
129
+ end
130
+
131
+
132
+ end
133
+
134
+
135
+
136
+ end
@@ -0,0 +1,3 @@
1
+ module Hollybush
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,151 @@
1
+ require 'spec_helper'
2
+
3
+ module Hollybush
4
+
5
+ describe List do
6
+ context "when storing in the DB with valid details" do
7
+ before(:each) do
8
+ @list = List.new(:name => "My New List")
9
+ @list.save
10
+ end
11
+ it "should have an id" do
12
+ @list.id.should_not be_nil
13
+ end
14
+ it "id should be of a String type" do
15
+ @list.id.should be_an_instance_of(String)
16
+ end
17
+ it "should have a name" do
18
+ @list.name.should == "My New List"
19
+ end
20
+ specify {@list.should be_valid}
21
+ context "when adding items into the list" do
22
+ before(:each) do
23
+ @list << {:description => "Here's an item"}
24
+ @list << {:description => "Here's another item", :state => "Started"}
25
+ end
26
+ specify { @list.should have(2).entries }
27
+
28
+ context "when deleting items from the list" do
29
+ before(:each) do
30
+ @list.delete_entry(@list.entries.first)
31
+ end
32
+ specify { @list.should have(1).entries }
33
+ end
34
+
35
+ context "when updating an item" do
36
+ before(:each) do
37
+ entry = @list.entries.first
38
+ entry["description"] = "Here's an updated entry"
39
+ @list.save
40
+ @updated_list = List.find(:_id => @list.id).first
41
+ end
42
+ it "should update an existing entry" do
43
+ @updated_list.entries.first["description"].should == "Here's an updated entry"
44
+ end
45
+ it "should not create or remove Lists" do
46
+ expect { @list.save }.not_to change(List, :count)
47
+ end
48
+ it "should not create or remove Entries in the Lists" do
49
+ @updated_list.should have(2).entries
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ context "when storing in the DB with invalid details" do
56
+ before(:each) do
57
+ @list = List.new(:name => nil)
58
+ @list.save
59
+ end
60
+ specify {@list.should_not be_valid}
61
+ it "should have an id" do
62
+ @list.id.should be_nil
63
+ end
64
+ it "should have an error on 'name'" do
65
+ @list.errors[:name].should == ["can't be blank"]
66
+ end
67
+ end
68
+
69
+ context "when updating a List" do
70
+ before(:each) do
71
+ @list = List.new(:name => "My New List")
72
+ @list.save
73
+ end
74
+ context "with valid details" do
75
+ before(:each) do
76
+ @list.name = "My Revised List"
77
+ @list.save
78
+ end
79
+ specify {@list.should be_valid}
80
+ it "should persist on save" do
81
+ List.find({"id" => @list.id}).first.name.should == "My Revised List"
82
+ end
83
+ end
84
+ context "with invalid details" do
85
+ before(:each) do
86
+ @list.name = nil
87
+ @list.save
88
+ end
89
+ specify {@list.should_not be_valid}
90
+ it "should leave persisted version of List unaffected" do
91
+ List.find({"id" => @list.id}).first.name.should == "My New List"
92
+ end
93
+ it "should have an error on 'name'" do
94
+ @list.errors[:name].should == ["can't be blank"]
95
+ end
96
+ end
97
+ context "with an attribute hash" do
98
+ before(:each) do
99
+ @list = List.create(:name => "My New List")
100
+ @attributes = {"name"=>"My Revised Shopping List", "entries" => [{"description"=>"entry 1"},{"description"=>"entry 2"}], "id"=>@list.id, "controller"=>"lists", "action"=>"update"}
101
+ @list.update_attributes(@attributes)
102
+ @list.save
103
+ end
104
+ specify{ @list.should be_valid }
105
+ it "should update the persisted version with name and entries" do
106
+ list = List.find({"id" => @list.id}).first
107
+ list.name.should == @attributes["name"]
108
+ list.entries.should =~ @attributes["entries"]
109
+ end
110
+ end
111
+
112
+ end
113
+
114
+ context "when retrieving from the DB" do
115
+ before(:each) do
116
+ @list = List.new(:name => "My New List", "entries" => [{"description" => "Here's an item"}])
117
+ @id = @list.save
118
+ List.new(:name => "My Second List", "entries" => [{"description" => "Here's another item"}]).save
119
+ end
120
+ it "should retrieve all lists by specifying no parameters" do
121
+ List.find.should have(2).entries
122
+ end
123
+ it "should retrieve specific lists by specifying some parameters" do
124
+ List.find("_id" => @id).first.id.should == @list.id
125
+ end
126
+ end
127
+
128
+ context "when deleting Lists" do
129
+ before(:each) do
130
+ @list1 = List.create(:name => "My first list")
131
+ @list2 = List.create(:name => "My second list")
132
+ end
133
+ context "deleting a single list" do
134
+ it "should reduce the List count by 1" do
135
+ expect { @list1.delete }.to change(List, :count).by(-1)
136
+ end
137
+ end
138
+ context "deleting Lists based on matching criteria" do
139
+ it "should reduce the List count by 2" do
140
+ expect { List.delete({:name => /My/}) }.to change(List, :count).by(-2)
141
+ end
142
+ end
143
+ context "deleting Lists based on non-matching criteria" do
144
+ it "should not reduce the List count" do
145
+ expect { List.delete({:name => /You/}) }.to_not change(List, :count)
146
+ end
147
+ end
148
+ end
149
+
150
+ end
151
+ end
@@ -0,0 +1,7 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '/../lib/hollybush'))
2
+
3
+ RSpec.configure do |config|
4
+ config.before(:each) do
5
+ Hollybush.mongodb.collections.select { |c| c.name != 'system.indexes' }.each(&:drop)
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,155 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hollybush
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.2
6
+ platform: ruby
7
+ authors:
8
+ - Ijonas Kisselbach
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-06-06 00:00:00 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: mongo
17
+ prerelease: false
18
+ requirement: &id001 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ type: :runtime
25
+ version_requirements: *id001
26
+ - !ruby/object:Gem::Dependency
27
+ name: mongo_ext
28
+ prerelease: false
29
+ requirement: &id002 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: "0"
35
+ type: :runtime
36
+ version_requirements: *id002
37
+ - !ruby/object:Gem::Dependency
38
+ name: bson
39
+ prerelease: false
40
+ requirement: &id003 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ type: :runtime
47
+ version_requirements: *id003
48
+ - !ruby/object:Gem::Dependency
49
+ name: bson_ext
50
+ prerelease: false
51
+ requirement: &id004 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ type: :runtime
58
+ version_requirements: *id004
59
+ - !ruby/object:Gem::Dependency
60
+ name: activemodel
61
+ prerelease: false
62
+ requirement: &id005 !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: "0"
68
+ type: :runtime
69
+ version_requirements: *id005
70
+ - !ruby/object:Gem::Dependency
71
+ name: activesupport
72
+ prerelease: false
73
+ requirement: &id006 !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: "0"
79
+ type: :runtime
80
+ version_requirements: *id006
81
+ - !ruby/object:Gem::Dependency
82
+ name: rspec
83
+ prerelease: false
84
+ requirement: &id007 !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: "0"
90
+ type: :development
91
+ version_requirements: *id007
92
+ - !ruby/object:Gem::Dependency
93
+ name: awesome_print
94
+ prerelease: false
95
+ requirement: &id008 !ruby/object:Gem::Requirement
96
+ none: false
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: "0"
101
+ type: :development
102
+ version_requirements: *id008
103
+ description: Light-weight flexible structured list implementation.
104
+ email:
105
+ - ijonas.kisselbach@gmail.com
106
+ executables: []
107
+
108
+ extensions: []
109
+
110
+ extra_rdoc_files: []
111
+
112
+ files:
113
+ - .gitignore
114
+ - .rvmrc
115
+ - CHANGELOG.markdown
116
+ - Gemfile
117
+ - README.markdown
118
+ - Rakefile
119
+ - hollybush.gemspec
120
+ - lib/hollybush.rb
121
+ - lib/hollybush/connectivity.rb
122
+ - lib/hollybush/list.rb
123
+ - lib/hollybush/version.rb
124
+ - spec/list_spec.rb
125
+ - spec/spec_helper.rb
126
+ homepage: http://github.com/ijonas/hollybush
127
+ licenses: []
128
+
129
+ post_install_message:
130
+ rdoc_options: []
131
+
132
+ require_paths:
133
+ - lib
134
+ required_ruby_version: !ruby/object:Gem::Requirement
135
+ none: false
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: "0"
140
+ required_rubygems_version: !ruby/object:Gem::Requirement
141
+ none: false
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: "0"
146
+ requirements: []
147
+
148
+ rubyforge_project: hollybush
149
+ rubygems_version: 1.8.5
150
+ signing_key:
151
+ specification_version: 3
152
+ summary: Flexible structured list manager backed by MongoDB.
153
+ test_files:
154
+ - spec/list_spec.rb
155
+ - spec/spec_helper.rb