zdzolton-cambric 0.5.0 → 0.6.0

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/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.0
1
+ 0.6.0
data/cambric.gemspec CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{cambric}
5
- s.version = "0.5.0"
5
+ s.version = "0.6.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Zachary Zolton", "Geoff Buesing"]
9
- s.date = %q{2009-05-29}
9
+ s.date = %q{2009-06-02}
10
10
  s.email = %q{zachary.zolton@gmail.com}
11
11
  s.extra_rdoc_files = [
12
12
  "LICENSE",
@@ -21,8 +21,18 @@ Gem::Specification.new do |s|
21
21
  "VERSION",
22
22
  "cambric.gemspec",
23
23
  "lib/cambric.rb",
24
- "spec/cambric_spec.rb",
24
+ "lib/cambric/assume_design_doc_name.rb",
25
+ "lib/cambric/configurator.rb",
26
+ "lib/cambric/test_helpers.rb",
27
+ "spec/cambric/assume_design_doc_name_spec.rb",
28
+ "spec/cambric/cambric_spec.rb",
29
+ "spec/cambric/configurator_spec.rb",
30
+ "spec/cambric/test_helpers_spec.rb",
25
31
  "spec/fixtures/twitter-clone/tweets/views/by_follower_and_created_at/map.js",
32
+ "spec/fixtures/twitter-clone/users/views/bad/map.js",
33
+ "spec/fixtures/twitter-clone/users/views/bad/reduce.js",
34
+ "spec/fixtures/twitter-clone/users/views/followers/map.js",
35
+ "spec/fixtures/twitter-clone/users/views/followers/reduce.js",
26
36
  "spec/spec.opts",
27
37
  "spec/spec_helper.rb"
28
38
  ]
@@ -32,7 +42,10 @@ Gem::Specification.new do |s|
32
42
  s.rubygems_version = %q{1.3.3}
33
43
  s.summary = %q{Opinionated management and usage of CouchDB from your Ruby apps.}
34
44
  s.test_files = [
35
- "spec/cambric_spec.rb",
45
+ "spec/cambric/assume_design_doc_name_spec.rb",
46
+ "spec/cambric/cambric_spec.rb",
47
+ "spec/cambric/configurator_spec.rb",
48
+ "spec/cambric/test_helpers_spec.rb",
36
49
  "spec/spec_helper.rb"
37
50
  ]
38
51
 
@@ -0,0 +1,15 @@
1
+ module Cambric
2
+ module AssumeDesignDocName
3
+
4
+ attr_accessor :cambric_design_doc_name
5
+
6
+ def view name, options={}, &block
7
+ super "#{@cambric_design_doc_name}/#{name}", options, &block
8
+ end
9
+
10
+ def cambric_design_doc
11
+ get "_design/#{@cambric_design_doc_name}"
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,34 @@
1
+ module Cambric
2
+ class Configurator
3
+
4
+ attr_accessor :design_doc_name, :db_dir, :environment, :databases
5
+
6
+ def initialize
7
+ @design_doc_name = 'cambric'
8
+ @db_dir = 'cambric'
9
+ @environment = 'development'
10
+ @databases = {}
11
+ end
12
+
13
+ def initialize_databases
14
+ dbs_by_name = {}
15
+ @databases.each_pair do |db,urls_by_env|
16
+ urls_by_env.keys.map!{ |env| env.to_sym }
17
+ uri = URI.parse urls_by_env[@environment.to_sym]
18
+ dbs_by_name[db.to_sym] = initialize_database uri
19
+ end
20
+ dbs_by_name
21
+ end
22
+
23
+ private
24
+
25
+ def initialize_database uri
26
+ server = CouchRest.new("#{uri.scheme}://#{uri.host}:#{uri.port}")
27
+ database = server.database uri.path.gsub(/^\//, '')
28
+ database.extend ::Cambric::AssumeDesignDocName
29
+ database.cambric_design_doc_name = @design_doc_name
30
+ database
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,96 @@
1
+ require 'open3'
2
+
3
+ module Cambric
4
+ module TestHelpers
5
+
6
+ class ReduceError < RuntimeError ; end
7
+
8
+ def execute_map db, view, doc
9
+ view_functions = Cambric[db].cambric_design_doc['views'][view.to_s]
10
+ execute_js <<-CODE
11
+ var emittedKeyValuePairs = [];
12
+ function emit(key, value) {
13
+ emittedKeyValuePairs.push({ 'key': key, 'value': value });
14
+ }
15
+ var mapFunction = #{view_functions['map']};
16
+ try { mapFunction(#{doc.to_json}); } catch (e) {}
17
+ returnValueToRuby(emittedKeyValuePairs);
18
+ CODE
19
+ end
20
+
21
+ def execute_reduce db, view, options
22
+ view_functions = Cambric[db].cambric_design_doc['views'][view.to_s]
23
+ options = { :rereduce => false }.merge(options)
24
+ execute_js <<-CODE
25
+ var reduceFunction = #{view_functions['reduce']};
26
+ try {
27
+ returnValueToRuby(reduceFunction(
28
+ #{(options[:keys] || []).to_json},
29
+ #{(options[:values] || []).to_json},
30
+ #{options[:rereduce]}
31
+ ));
32
+ } catch (error) {
33
+ raiseErrorToRuby(error);
34
+ }
35
+ CODE
36
+ end
37
+
38
+ private
39
+
40
+ def execute_js code
41
+ output = nil
42
+ Open3.popen3 'js' do |stdin, stdout, stderr|
43
+ stdin.puts HELPER_FUNCTIONS
44
+ stdin.puts code
45
+ stdin.close
46
+ output = JSON.parse(stdout.read)
47
+ end
48
+ raise ReduceError, output['error'] if output.has_key?('error')
49
+ output['result']
50
+ end
51
+
52
+ HELPER_FUNCTIONS = <<-HELPERS
53
+ function sum(values) {
54
+ var total = 0;
55
+ values.forEach(function(v) { total += v; });
56
+ return total;
57
+ }
58
+
59
+ function toJSON(obj) {
60
+ switch (typeof obj) {
61
+ case 'object':
62
+ if (obj) {
63
+ var list = [];
64
+ if (obj instanceof Array) {
65
+ for (var i=0;i < obj.length;i++) {
66
+ list.push(toJSON(obj[i]));
67
+ }
68
+ return '[' + list.join(',') + ']';
69
+ } else {
70
+ for (var prop in obj) {
71
+ list.push('"' + prop + '":' + toJSON(obj[prop]));
72
+ }
73
+ return '{' + list.join(',') + '}';
74
+ }
75
+ } else {
76
+ return 'null';
77
+ }
78
+ case 'string':
79
+ return '"' + obj.replace(/(["'])/g, '\\'') + '"';
80
+ case 'number':
81
+ case 'boolean':
82
+ return new String(obj);
83
+ }
84
+ }
85
+
86
+ function returnValueToRuby(value) {
87
+ print(toJSON({ 'result': value }));
88
+ }
89
+
90
+ function raiseErrorToRuby(error) {
91
+ print(toJSON({ 'error': error['message'] }));
92
+ }
93
+ HELPERS
94
+
95
+ end
96
+ end
data/lib/cambric.rb CHANGED
@@ -1,6 +1,8 @@
1
1
  require 'couchrest'
2
2
  require 'uri'
3
3
 
4
+ Dir.glob(File.join(File.dirname(__FILE__), 'cambric/**.rb')).each{ |f| require f }
5
+
4
6
  module Cambric
5
7
 
6
8
  def self.design_doc_name
@@ -66,46 +68,3 @@ private
66
68
  end
67
69
 
68
70
  end
69
-
70
- class Cambric::Configurator
71
-
72
- attr_accessor :design_doc_name, :db_dir, :environment, :databases
73
-
74
- def initialize
75
- @design_doc_name = 'cambric'
76
- @db_dir = 'cambric'
77
- @environment = 'development'
78
- @databases = {}
79
- end
80
-
81
- def initialize_databases
82
- dbs_by_name = {}
83
- @databases.each_pair do |db,urls_by_env|
84
- urls_by_env.keys.map!{ |env| env.to_sym }
85
- uri = URI.parse urls_by_env[@environment.to_sym]
86
- dbs_by_name[db.to_sym] = initialize_database uri
87
- end
88
- dbs_by_name
89
- end
90
-
91
- private
92
-
93
- def initialize_database uri
94
- server = CouchRest.new("#{uri.scheme}://#{uri.host}:#{uri.port}")
95
- database = server.database uri.path.gsub(/^\//, '')
96
- database.extend ::Cambric::AssumeDesignDocName
97
- database.cambric_design_doc_name = @design_doc_name
98
- database
99
- end
100
-
101
- end
102
-
103
- module Cambric::AssumeDesignDocName
104
-
105
- attr_accessor :cambric_design_doc_name
106
-
107
- def view name, options={}, &block
108
- super "#{@cambric_design_doc_name}/#{name}", options, &block
109
- end
110
-
111
- end
@@ -0,0 +1,22 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))
2
+
3
+ describe Cambric::AssumeDesignDocName do
4
+
5
+ describe "after pushing design docs" do
6
+ before :all do
7
+ configure_twitter_clone
8
+ Cambric.prepare_databases!
9
+ end
10
+
11
+ after(:all){ delete_twitter_clone_databases }
12
+
13
+ it "should be able to query view without re-specifying design doc name" do
14
+ Cambric[:tweets].view 'by_follower_and_created_at'
15
+ end
16
+
17
+ it "should get the design doc specified by configuration" do
18
+ Cambric[:tweets].cambric_design_doc.should_not be_nil
19
+ end
20
+ end
21
+
22
+ end
@@ -1,30 +1,6 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))
2
2
  require 'uri'
3
3
 
4
- TWITTER_CLONE_DATABASES = {
5
- :users => {
6
- :development => 'http://127.0.0.1:5984/users-development',
7
- :test => 'http://127.0.0.1:5984/users-testing'
8
- },
9
- :tweets => {
10
- :development => 'http://127.0.0.1:5984/tweets-development',
11
- :test => 'http://127.0.0.1:5984/tweets-testing'
12
- }
13
- }
14
-
15
- def configure_twitter_clone
16
- Cambric.configure do |config|
17
- config.design_doc_name = 'twitter-clone'
18
- config.db_dir = 'spec/fixtures/twitter-clone'
19
- config.environment = 'test'
20
- config.databases = TWITTER_CLONE_DATABASES
21
- end
22
- end
23
-
24
- def delete_twitter_clone_databases
25
- %w(users tweets).each{ |db| Cambric[db].delete! rescue nil }
26
- end
27
-
28
4
  describe Cambric do
29
5
 
30
6
  describe "after configuring without a block" do
@@ -141,10 +117,6 @@ describe Cambric do
141
117
  design_doc = Cambric[:tweets].get("_design/twitter-clone")
142
118
  design_doc['views']['by_follower_and_created_at'].should_not be_nil
143
119
  end
144
-
145
- it "should be able to query view without re-specifying design doc name" do
146
- Cambric[:tweets].view 'by_follower_and_created_at'
147
- end
148
120
  end
149
121
 
150
122
  describe "when the design doc already exists" do
@@ -211,34 +183,3 @@ describe Cambric do
211
183
  end
212
184
 
213
185
  end
214
-
215
- describe Cambric::Configurator do
216
- before :all do
217
- @config = Cambric::Configurator.new
218
- end
219
-
220
- it "should default its design doc name to 'cambric'" do
221
- @config.design_doc_name.should == 'cambric'
222
- end
223
-
224
- it "should default to 'cambric' for the database directory" do
225
- @config.db_dir.should == 'cambric'
226
- end
227
-
228
- it "should default to 'development' for the environment" do
229
- @config.environment.should == 'development'
230
- end
231
-
232
- describe "when retrieving the configured CouchRest::Database instances" do
233
- before :all do
234
- @config.databases = TWITTER_CLONE_DATABASES
235
- @dbs = @config.initialize_databases
236
- end
237
-
238
- it "should have the expected URLs for development environment" do
239
- %w(users tweets).each do |db|
240
- @dbs[db.to_sym].uri.should == "http://127.0.0.1:5984/#{db}-development"
241
- end
242
- end
243
- end
244
- end
@@ -0,0 +1,32 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))
2
+
3
+ describe Cambric::Configurator do
4
+ before :all do
5
+ @config = Cambric::Configurator.new
6
+ end
7
+
8
+ it "should default its design doc name to 'cambric'" do
9
+ @config.design_doc_name.should == 'cambric'
10
+ end
11
+
12
+ it "should default to 'cambric' for the database directory" do
13
+ @config.db_dir.should == 'cambric'
14
+ end
15
+
16
+ it "should default to 'development' for the environment" do
17
+ @config.environment.should == 'development'
18
+ end
19
+
20
+ describe "when retrieving the configured CouchRest::Database instances" do
21
+ before :all do
22
+ @config.databases = TWITTER_CLONE_DATABASES
23
+ @dbs = @config.initialize_databases
24
+ end
25
+
26
+ it "should have the expected URLs for development environment" do
27
+ %w(users tweets).each do |db|
28
+ @dbs[db.to_sym].uri.should == "http://127.0.0.1:5984/#{db}-development"
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,51 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))
2
+
3
+ describe Cambric::TestHelpers do
4
+
5
+ include Cambric::TestHelpers
6
+
7
+ before :all do
8
+ configure_twitter_clone
9
+ Cambric.prepare_databases!
10
+ end
11
+
12
+ after(:all){ delete_twitter_clone_databases }
13
+
14
+ describe "testing a view's map function" do
15
+ it "should return an array, with an element for each call to emit()" do
16
+ kv_pairs = execute_map :users, :followers,
17
+ '_id' => 'poddle', 'following' => ['jack', 'russel']
18
+ kv_pairs.size.should == 2
19
+ kv_pairs[0]['key'].should == 'jack'
20
+ kv_pairs[1]['key'].should == 'russel'
21
+ kv_pairs[0]['value'].should == 'poddle'
22
+ kv_pairs[1]['value'].should == 'poddle'
23
+ end
24
+
25
+ it "should return an empty array when documents cause an exception" do
26
+ kv_pairs = execute_map :users, :bad, "doesn't" => 'matter'
27
+ kv_pairs.length.should == 1
28
+ end
29
+ end
30
+
31
+ describe "testing a view's reduce function" do
32
+
33
+ it "should default to false for rereduce" do
34
+ result = execute_reduce :users, :followers, :values => ['dr', 'quinn', 'medicine', 'woman']
35
+ result.should == 4
36
+ end
37
+
38
+ it "should be able to execute a rereduce" do
39
+ result = execute_reduce :users, :followers, :values => [4, 5, 6], :rereduce => true
40
+ result.should == 15
41
+ end
42
+
43
+ it "should forward exceptions to Ruby" do
44
+ lambda do
45
+ execute_reduce :users, :bad, :values => ['what', 'ever']
46
+ end.should raise_error(Cambric::TestHelpers::ReduceError)
47
+ end
48
+
49
+ end
50
+
51
+ end
@@ -0,0 +1,7 @@
1
+ function(doc) {
2
+ // This should be returned:
3
+ emit(4, 5);
4
+
5
+ // This should not:
6
+ emit(doc['some_non_existant_property'].length, null);
7
+ }
@@ -0,0 +1,4 @@
1
+ function(key, values) {
2
+ // This should throw an error:
3
+ return values[0]['some_non_existant_property'].length;
4
+ }
@@ -0,0 +1,6 @@
1
+ function(doc) {
2
+ // FYI: This example assumes we're using usernames as the doc ID.
3
+ doc['following'].forEach(function(user) {
4
+ emit(user, doc['_id']);
5
+ });
6
+ }
@@ -0,0 +1,7 @@
1
+ function(keys, values, rereduce) {
2
+ if (rereduce) {
3
+ return sum(values);
4
+ } else {
5
+ return values.length;
6
+ }
7
+ }
data/spec/spec_helper.rb CHANGED
@@ -12,12 +12,34 @@ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
12
12
 
13
13
  require 'cambric'
14
14
 
15
- FIXTURES_PATH = './spec/fixtures'
15
+ ##############
16
16
 
17
- def load_fixture *path
18
- open(File.expand_path(File.join %w(spec fixtures) + path))
17
+ TWITTER_CLONE_DATABASES = {
18
+ :users => {
19
+ :development => 'http://127.0.0.1:5984/users-development',
20
+ :test => 'http://127.0.0.1:5984/users-testing'
21
+ },
22
+ :tweets => {
23
+ :development => 'http://127.0.0.1:5984/tweets-development',
24
+ :test => 'http://127.0.0.1:5984/tweets-testing'
25
+ }
26
+ }
27
+
28
+ def configure_twitter_clone
29
+ Cambric.configure do |config|
30
+ config.design_doc_name = 'twitter-clone'
31
+ config.db_dir = 'spec/fixtures/twitter-clone'
32
+ config.environment = 'test'
33
+ config.databases = TWITTER_CLONE_DATABASES
34
+ end
35
+ end
36
+
37
+ def delete_twitter_clone_databases
38
+ %w(users tweets).each{ |db| Cambric[db].delete! rescue nil }
19
39
  end
20
40
 
41
+ #############
42
+
21
43
  Spec::Runner.configure do |config|
22
44
 
23
45
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zdzolton-cambric
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zachary Zolton
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2009-05-29 00:00:00 -07:00
13
+ date: 2009-06-02 00:00:00 -07:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -41,8 +41,18 @@ files:
41
41
  - VERSION
42
42
  - cambric.gemspec
43
43
  - lib/cambric.rb
44
- - spec/cambric_spec.rb
44
+ - lib/cambric/assume_design_doc_name.rb
45
+ - lib/cambric/configurator.rb
46
+ - lib/cambric/test_helpers.rb
47
+ - spec/cambric/assume_design_doc_name_spec.rb
48
+ - spec/cambric/cambric_spec.rb
49
+ - spec/cambric/configurator_spec.rb
50
+ - spec/cambric/test_helpers_spec.rb
45
51
  - spec/fixtures/twitter-clone/tweets/views/by_follower_and_created_at/map.js
52
+ - spec/fixtures/twitter-clone/users/views/bad/map.js
53
+ - spec/fixtures/twitter-clone/users/views/bad/reduce.js
54
+ - spec/fixtures/twitter-clone/users/views/followers/map.js
55
+ - spec/fixtures/twitter-clone/users/views/followers/reduce.js
46
56
  - spec/spec.opts
47
57
  - spec/spec_helper.rb
48
58
  has_rdoc: false
@@ -72,5 +82,8 @@ signing_key:
72
82
  specification_version: 3
73
83
  summary: Opinionated management and usage of CouchDB from your Ruby apps.
74
84
  test_files:
75
- - spec/cambric_spec.rb
85
+ - spec/cambric/assume_design_doc_name_spec.rb
86
+ - spec/cambric/cambric_spec.rb
87
+ - spec/cambric/configurator_spec.rb
88
+ - spec/cambric/test_helpers_spec.rb
76
89
  - spec/spec_helper.rb