addywaddy-couch_surfer 0.0.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/LICENSE ADDED
File without changes
data/README.md ADDED
@@ -0,0 +1,73 @@
1
+ CouchSurfer
2
+ ===========
3
+
4
+ Description
5
+ -----------
6
+ CouchSurfer is an extraction of CouchRest::Model from the excellent [CouchRest](http://github.com/jchris/couchrest/ "CouchRest") gem by J. Chris Anderson.
7
+
8
+ Features
9
+ --------
10
+ - ORM (Extracted from CouchRest::Model)
11
+ - Associations
12
+ - `has_ many`
13
+ - `belongs_to`
14
+
15
+ - Validations
16
+ - All validations from the [Validatable](http://github.com/jrun/validatable/ "Validatable") gem
17
+ - `validates_uniqueness_of`
18
+
19
+ Examples
20
+ --------
21
+ class Account
22
+ include CouchSurfer::Model
23
+ include CouchSurfer::Associations
24
+
25
+ key_accessor :name
26
+
27
+ # Will use the Project.by_account_id view with {:key => account_instance.id}
28
+ has_many :projects
29
+
30
+ # Uses a custom view and key
31
+ has_many :employees, :view => {:name => :by_account_id_and_email,
32
+ :query => lambda{ {:startkey => [id, nil], :endkey => [id, {}]} }}
33
+
34
+ end
35
+
36
+ class Project
37
+ include CouchSurfer::Model
38
+ include CouchSurfer::Associations
39
+
40
+ key_accessor :name, :account_id
41
+
42
+ belongs_to :account
43
+
44
+ view_by :account_id
45
+ end
46
+
47
+
48
+ class Employee
49
+ include CouchSurfer::Model
50
+ include CouchSurfer::Associations
51
+ include CouchSurfer::Validations
52
+
53
+ key_accessor :email, :account_id
54
+ belongs_to :account
55
+
56
+ view_by :account_id, :email
57
+ view_by :name
58
+
59
+ validates_presence_of :name
60
+ validates_format_of :email,
61
+ :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i
62
+ validates_length_of :postcode, :is => 7, :message => "not the correct length"
63
+
64
+ # Will use the Employee.by_name view with {:key => employee_instance.name}
65
+ validates_uniqueness_of :name, :message => "No two Beatles have the same name"
66
+
67
+ # Uses a custom view and key
68
+ validates_uniqueness_of :email, :view => {:name => :by_account_id_and_email,
69
+ :query => lambda{ {:key => [account_id, email]} }}, :message => "Already taken!"
70
+
71
+ end
72
+
73
+ Please check out the specs as well :)
data/Rakefile ADDED
@@ -0,0 +1,67 @@
1
+ require 'rake'
2
+ require "rake/rdoctask"
3
+ require 'rake/gempackagetask'
4
+ require File.join(File.expand_path(File.dirname(__FILE__)),'lib','couch_surfer')
5
+
6
+
7
+ begin
8
+ require 'spec/rake/spectask'
9
+ rescue LoadError
10
+ puts <<-EOS
11
+ To use rspec for testing you must install rspec gem:
12
+ gem install rspec
13
+ EOS
14
+ exit(0)
15
+ end
16
+
17
+ spec = Gem::Specification.new do |s|
18
+ s.name = "couch_surfer"
19
+ s.version = CouchSurfer::VERSION
20
+ s.date = "2009-01-22"
21
+ s.summary = "ORM based on CouchRest::Model"
22
+ s.email = "jchris@apache.org"
23
+ s.homepage = "http://github.com/addywaddy/couchsurfer"
24
+ s.description = "CouchSurfer provides an ORM for CouchDB, as well as supporting association and validation declarations."
25
+ s.has_rdoc = true
26
+ s.authors = ["Adam Groves"]
27
+ s.files = %w( LICENSE README.md Rakefile ) +
28
+ Dir["{lib,spec}/**/*"] -
29
+ Dir["spec/tmp"]
30
+ s.extra_rdoc_files = %w( README.md LICENSE )
31
+ s.require_path = "lib"
32
+ s.add_dependency("json", ">= 1.1.2")
33
+ s.add_dependency("rest-client", ">= 0.5")
34
+ s.add_dependency('jchris-couchrest', ">= 0.12.2")
35
+ end
36
+
37
+
38
+ desc "create .gemspec file (useful for github)"
39
+ task :gemspec do
40
+ filename = "#{spec.name}.gemspec"
41
+ File.open(filename, "w") do |f|
42
+ f.puts spec.to_ruby
43
+ end
44
+ end
45
+
46
+ desc "Run all specs"
47
+ Spec::Rake::SpecTask.new('spec') do |t|
48
+ t.spec_files = FileList['spec/**/*_spec.rb']
49
+ end
50
+
51
+ desc "Print specdocs"
52
+ Spec::Rake::SpecTask.new(:doc) do |t|
53
+ t.spec_opts = ["--format", "specdoc"]
54
+ t.spec_files = FileList['spec/*_spec.rb']
55
+ end
56
+
57
+ desc "Generate the rdoc"
58
+ Rake::RDocTask.new do |rdoc|
59
+ files = ["README.rdoc", "LICENSE", "lib/**/*.rb"]
60
+ rdoc.rdoc_files.add(files)
61
+ rdoc.main = "README.rdoc"
62
+ rdoc.title = "CouchRest: Ruby CouchDB, close to the metal"
63
+ end
64
+
65
+ desc "Run the rspec"
66
+ task :default => :spec
67
+
@@ -0,0 +1,57 @@
1
+ require 'rubygems'
2
+ require 'extlib'
3
+
4
+ module CouchSurfer
5
+ module Associations
6
+ module ClassMethods
7
+ def has_many *args
8
+ options = args.last.is_a?(Hash) ? args.pop : {}
9
+ children = args.first
10
+ define_method children do |*args|
11
+ query_params = args.last.is_a?(Hash) ? args.pop : nil
12
+ name = ::Extlib::Inflection.camelize(children.to_s.singular)
13
+ klass = ::Extlib::Inflection.constantize(name)
14
+ if options[:view].is_a?(Hash)
15
+ view_name = options[:view][:name]
16
+ query = options[:view][:query].is_a?(Proc) ? self.instance_eval(&options[:view][:query]) : nil
17
+ end
18
+ view_name ||= "by_#{self.class.name.downcase}_id"
19
+ query ||= {:key => self.id}
20
+ klass.send(view_name, query)
21
+ end
22
+ end
23
+
24
+ def belongs_to *args
25
+ options = args.last.is_a?(Hash) ? args.pop : {}
26
+ parent = args.first
27
+ # view_key = "#{parent}_id".to_sym
28
+ # if options[:identifiers]
29
+ # if options[:prepend]
30
+ # view_key = options[:identifiers] << view_key
31
+ # else
32
+ # view_key = options[:identifiers].unshift(view_key)
33
+ # end
34
+ # end
35
+ # class_eval do
36
+ # view_by *view_key
37
+ # end
38
+ define_method parent do
39
+ name = ::Extlib::Inflection.camelize(parent.to_s)
40
+ klass = ::Extlib::Inflection.constantize(name)
41
+ parent_id = self["#{parent.to_s}_id"]
42
+ if parent_id
43
+ klass.send(:get, self["#{parent.to_s}_id"])
44
+ end
45
+ end
46
+
47
+ define_method "#{parent}=".to_sym do |parent_obj|
48
+ self["#{parent_obj.class.name.downcase}_id"] = parent_obj.id
49
+ end
50
+ end
51
+ end
52
+
53
+ def self.included(receiver)
54
+ receiver.extend ClassMethods
55
+ end
56
+ end
57
+ end