thingtank 0.2.0 → 0.3.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/Gemfile +1 -0
- data/README.md +1 -1
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/lib/couchrest/extensions/list.rb +169 -0
- data/lib/couchrest/extensions/view.rb +14 -1
- data/lib/thingtank/callbacks.rb +2 -1
- data/lib/thingtank/character.rb +19 -0
- data/lib/thingtank.rb +3 -0
- data/test/test_lists.rb +294 -0
- data/test/test_views.rb +25 -0
- metadata +41 -28
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
thingtank:
|
1
|
+
thingtank: couchrest docs with multiple characters
|
2
2
|
=======================================================================
|
3
3
|
|
4
4
|
[](https://secure.travis-ci.org/metakeule/thingtank)
|
data/Rakefile
CHANGED
@@ -17,7 +17,7 @@ Jeweler::Tasks.new do |gem|
|
|
17
17
|
gem.name = "thingtank"
|
18
18
|
gem.homepage = "http://github.com/metakeule/thingtank"
|
19
19
|
gem.license = "MIT"
|
20
|
-
gem.summary = %Q{
|
20
|
+
gem.summary = %Q{couchrest docs with multiple characters}
|
21
21
|
gem.email = "Base64.decode64(bGludXhAbWFyY3JlbmVhcm5zLmRl\n)"
|
22
22
|
gem.authors = ["Marc Rene Arns"]
|
23
23
|
# dependencies defined in Gemfile
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
@@ -0,0 +1,169 @@
|
|
1
|
+
# https://raw.github.com/couchrest/couchrest/master/lib/couchrest/design.rb
|
2
|
+
module CouchRest
|
3
|
+
class Design < Document
|
4
|
+
|
5
|
+
# Dispatches to any named list.
|
6
|
+
# (using the database where this design doc was saved)
|
7
|
+
def list list_name, query={}, &block
|
8
|
+
list_on database, list_name, query, &block
|
9
|
+
end
|
10
|
+
|
11
|
+
# Dispatches to any named list in a specific database
|
12
|
+
def list_on db, list_name, view_name, query = {}, &block
|
13
|
+
raise ArgumentError, "List query options must be set as symbols!" if query.keys.find{|k| k.is_a?(String)}
|
14
|
+
list_name = list_name.to_s
|
15
|
+
list_slug = "#{name}/#{list_name}/#{view_name}"
|
16
|
+
# Set the default query options
|
17
|
+
query = list_defaults(list_name).merge(query)
|
18
|
+
|
19
|
+
db.list(list_slug, query, &block)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Return the hash of default values to include in all queries sent
|
23
|
+
# to a list from couchrest.
|
24
|
+
def list_defaults(name)
|
25
|
+
(self['lists'][name.to_s] && self['lists'][name.to_s]["couchrest-defaults"]) || {}
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns true or false if the view is available.
|
29
|
+
def has_list?(name)
|
30
|
+
!self['lists'][name.to_s].nil?
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def fetch_list list_name, opts, &block
|
36
|
+
database.list(list_name, opts, &block)
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# https://raw.github.com/couchrest/couchrest/master/lib/couchrest/database.rb
|
43
|
+
module CouchRest
|
44
|
+
class Database
|
45
|
+
# == List based queries
|
46
|
+
# Query a CouchDB list as defined by a <tt>_design</tt> document. Accepts
|
47
|
+
# paramaters as described in http://wiki.apache.org/couchdb/HttpViewApi
|
48
|
+
def list(name, params = {}, payload = {}, &block)
|
49
|
+
payload['keys'] = params.delete(:keys) if params[:keys]
|
50
|
+
#params.delete(:keys)
|
51
|
+
# Try recognising the name, otherwise assume already prepared
|
52
|
+
list_path = name_to_list_path(name)
|
53
|
+
url = CouchRest.paramify_url "#{@root}/#{list_path}", params
|
54
|
+
#p [:url, url]
|
55
|
+
if block_given?
|
56
|
+
if !payload.empty?
|
57
|
+
@streamer.post url, payload, &block
|
58
|
+
else
|
59
|
+
@streamer.get url, &block
|
60
|
+
end
|
61
|
+
else
|
62
|
+
if !payload.empty?
|
63
|
+
CouchRest.post url, payload
|
64
|
+
else
|
65
|
+
CouchRest.get url
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
# Convert a simplified list name into a complete list path. If
|
72
|
+
# the name already starts with a "_" no alterations will be made.
|
73
|
+
def name_to_list_path(name)
|
74
|
+
name =~ /^([^_].+?)\/(.*)$/ ? "_design/#{$1}/_list/#{$2}" : name
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# analogous to https://github.com/couchrest/couchrest_model/blob/master/lib/couchrest/model/designs/view.rb
|
80
|
+
module CouchRest
|
81
|
+
module Model
|
82
|
+
module Designs
|
83
|
+
class List < View
|
84
|
+
|
85
|
+
attr_accessor :view_name
|
86
|
+
|
87
|
+
def initialize(parent, new_query = {}, name = nil, view_name)
|
88
|
+
self.view_name = view_name
|
89
|
+
super(parent, new_query, name)
|
90
|
+
end
|
91
|
+
|
92
|
+
# == List Execution Methods
|
93
|
+
#
|
94
|
+
# Request to the CouchDB database using the current query values.
|
95
|
+
|
96
|
+
# Return each row wrapped in a ViewRow object. Unlike the raw
|
97
|
+
# CouchDB request, this will provide an empty array if there
|
98
|
+
# are no results.
|
99
|
+
def rows
|
100
|
+
return @rows if @rows
|
101
|
+
if execute && result['rows']
|
102
|
+
@rows ||= result['rows'].map{|v| ViewRow.new(v, model)}
|
103
|
+
else
|
104
|
+
[ ]
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def execute
|
109
|
+
return self.result if result
|
110
|
+
raise "Database must be defined in model or list!" if use_database.nil?
|
111
|
+
|
112
|
+
# Remove the reduce value if its not needed to prevent CouchDB errors
|
113
|
+
#query.delete(:reduce) unless can_reduce?
|
114
|
+
|
115
|
+
if model.send(view_name.to_sym).can_reduce?
|
116
|
+
query[:reduce] = false if query[:include_docs] # don't reduce if we include_docs
|
117
|
+
end
|
118
|
+
|
119
|
+
model.save_design_doc(use_database)
|
120
|
+
|
121
|
+
self.result = model.design_doc.list_on(use_database, name, view_name, query.reject{|k,v| v.nil?})
|
122
|
+
end
|
123
|
+
|
124
|
+
class << self
|
125
|
+
# Simplified list creation. A new list will be added to the
|
126
|
+
# provided model's design document using the name and options.
|
127
|
+
#
|
128
|
+
# If the view name starts with "by_" and +:by+ is not provided in
|
129
|
+
# the options, the new list's map method will be interpreted and
|
130
|
+
# generated automatically. For example:
|
131
|
+
#
|
132
|
+
# List.create(Meeting, "by_date_and_name")
|
133
|
+
#
|
134
|
+
# Will create a list that searches by the date and name properties.
|
135
|
+
# Explicity setting the attributes to use is possible using the
|
136
|
+
# +:by+ option. For example:
|
137
|
+
#
|
138
|
+
# List.create(Meeting, "by_date_and_name", :by => [:date, :firstname, :lastname])
|
139
|
+
#
|
140
|
+
def create(model, name, function)
|
141
|
+
model.design_doc['lists'] ||= {}
|
142
|
+
list = model.design_doc['lists'][name.to_s] = function
|
143
|
+
list
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
|
152
|
+
# https://github.com/couchrest/couchrest_model/blob/master/lib/couchrest/model/designs/view.rb overwritten
|
153
|
+
|
154
|
+
class CouchRest::Model::Designs::DesignMapper
|
155
|
+
|
156
|
+
def list(name, function)
|
157
|
+
CouchRest::Model::Designs::List.create(model, name, function) if model.auto_update_design_doc
|
158
|
+
create_list_method(name)
|
159
|
+
end
|
160
|
+
|
161
|
+
def create_list_method(name)
|
162
|
+
model.class_eval <<-EOS, __FILE__, __LINE__ + 1
|
163
|
+
def self.list_#{name}(view_name, opts = {})
|
164
|
+
CouchRest::Model::Designs::List.new(self, opts, '#{name}', view_name)
|
165
|
+
end
|
166
|
+
EOS
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
@@ -4,11 +4,24 @@ class CouchRest::Model::Designs::DesignMapper
|
|
4
4
|
|
5
5
|
# generate a view to show only ThingTanks of a certain character, define them all in a ThingTank subclass (not in a character)
|
6
6
|
def character_view(klass, name, opts={})
|
7
|
-
name = "#{klass.to_s.
|
7
|
+
name = "#{klass.to_s.underscore.gsub('/', '_')}_#{name}"
|
8
8
|
opts ||= {}
|
9
9
|
opts[:guards] ||= []
|
10
10
|
# there is no "inArray" like function in couchdb, see http://stackoverflow.com/questions/3740464/i-have-to-write-every-function-i-need-for-couchdb
|
11
11
|
opts[:guards] << "((doc['characters'] !== undefined) && (function (item,arr) { for(p=0;p<arr.length;p++) if (item == arr[p]) return true; return false;})('#{klass.to_s}',doc['characters']))"
|
12
|
+
if opts[:emit]
|
13
|
+
# taken from # View#create and modified since there is no support for :emit
|
14
|
+
opts[:allow_blank] = opts[:allow_blank].nil? ? true : opts[:allow_blank]
|
15
|
+
opts[:guards] ||= []
|
16
|
+
opts[:guards].push "(doc['#{model.model_type_key}'] == '#{model.to_s}')"
|
17
|
+
opts[:map] = <<-EOF
|
18
|
+
function(doc) {
|
19
|
+
if (#{opts[:guards].join(' && ')}) {
|
20
|
+
#{opts[:emit]}
|
21
|
+
}
|
22
|
+
}
|
23
|
+
EOF
|
24
|
+
end
|
12
25
|
view(name, opts)
|
13
26
|
end
|
14
27
|
|
data/lib/thingtank/callbacks.rb
CHANGED
@@ -19,7 +19,8 @@ class ThingTank
|
|
19
19
|
before_destroy do
|
20
20
|
ok = true
|
21
21
|
(self["characters"] || []).each do |klass|
|
22
|
-
|
22
|
+
real_klass = self.class.const_get("Character").__subclasses()[klass.to_sym]
|
23
|
+
document = self.as(real_klass)
|
23
24
|
(ok = false) if false == document.run_callbacks(:destroy) do
|
24
25
|
true
|
25
26
|
end
|
data/lib/thingtank/character.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
Defined.enable!
|
1
2
|
|
2
3
|
class ThingTank
|
3
4
|
|
@@ -7,10 +8,28 @@ class ThingTank
|
|
7
8
|
include ThingTank::SharedMethods
|
8
9
|
|
9
10
|
class << self
|
11
|
+
|
12
|
+
# we need this hack with after_inherited and defined or active record is going wild, see: http://stackoverflow.com/questions/790626/ruby-can-i-have-something-like-classinherited-thats-triggered-only-after-the
|
13
|
+
# 'I'm trying to add behavior to activerecord models, but I need all the model customizations to go through before I mess with it. I'm trying to add behavior to activerecord models, but I need all the model customizations to go through before I mess with it. '
|
14
|
+
# exactly my case
|
15
|
+
# simple inherited leads to chaos here
|
16
|
+
def after_inherited(child)
|
17
|
+
@__sub_classes ||= {}
|
18
|
+
@__sub_classes[child.to_s.to_sym] = child
|
19
|
+
end
|
20
|
+
|
21
|
+
def defined(*args)
|
22
|
+
superclass.after_inherited(self) if superclass.respond_to?(:after_inherited)
|
23
|
+
end
|
24
|
+
|
25
|
+
def __subclasses
|
26
|
+
@__sub_classes ||= {}
|
27
|
+
end
|
10
28
|
|
11
29
|
def property(name, *args)
|
12
30
|
@character_properties ||= []
|
13
31
|
@character_properties << name.to_s
|
32
|
+
#p [:prop, self.name, @character_properties]
|
14
33
|
super
|
15
34
|
end
|
16
35
|
|
data/lib/thingtank.rb
CHANGED
@@ -2,12 +2,15 @@ if RUBY_VERSION =~ /1.8/
|
|
2
2
|
require 'backports'
|
3
3
|
end
|
4
4
|
|
5
|
+
require "defined"
|
6
|
+
|
5
7
|
# TODO
|
6
8
|
# - check if we could get useful inspiration from https://github.com/givmo/couch_record
|
7
9
|
# - improve views
|
8
10
|
# - validation for characters
|
9
11
|
|
10
12
|
require_relative File.join('thingtank', 'thingtank.rb')
|
13
|
+
require_relative File.join('couchrest', 'extensions', 'list.rb')
|
11
14
|
require_relative File.join('couchrest', 'extensions', 'view.rb')
|
12
15
|
require_relative File.join('thingtank', 'dependencies.rb')
|
13
16
|
require_relative File.join('thingtank', 'callbacks.rb')
|
data/test/test_lists.rb
ADDED
@@ -0,0 +1,294 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'pp'
|
3
|
+
|
4
|
+
class Car < ThingTank::Character
|
5
|
+
property :name
|
6
|
+
property :project
|
7
|
+
end
|
8
|
+
|
9
|
+
class House < ThingTank::Character
|
10
|
+
property :name
|
11
|
+
property :project
|
12
|
+
end
|
13
|
+
|
14
|
+
$list_filter = "function(head, req) {
|
15
|
+
var row;
|
16
|
+
var rows = [];
|
17
|
+
var debug = [];
|
18
|
+
var list_filter = {};
|
19
|
+
if(req.query['list_filter']){
|
20
|
+
list_filter = JSON.parse(req.query['list_filter']);
|
21
|
+
}
|
22
|
+
while(row = getRow()) {
|
23
|
+
if(list_filter){
|
24
|
+
var add = true;
|
25
|
+
for(fi in list_filter){
|
26
|
+
var filter_array = list_filter[fi];
|
27
|
+
if(filter_array){
|
28
|
+
var doc_val = row.doc;
|
29
|
+
var filter_key = filter_array[0];
|
30
|
+
var filter_val = filter_array[1];
|
31
|
+
if(doc_val){
|
32
|
+
var fkeys = filter_key.split('.'); /* filter_key may be data.page.disabled, so we have to get through that */
|
33
|
+
for(fk in fkeys){
|
34
|
+
if(doc_val !== undefined)
|
35
|
+
doc_val = doc_val[fkeys[fk]];
|
36
|
+
}
|
37
|
+
if(doc_val !== filter_val){
|
38
|
+
add = false;
|
39
|
+
}
|
40
|
+
} else {
|
41
|
+
if(Object.prototype.toString.call(row.value) === '[object Array]'){
|
42
|
+
debug[debug.length] = ['array', row.value[fi], filter_val];
|
43
|
+
if(row.value[fi] !== filter_val){
|
44
|
+
add = false;
|
45
|
+
}
|
46
|
+
|
47
|
+
} else {
|
48
|
+
debug[debug.length] = ['no_array', row.value, filter_val];
|
49
|
+
if(row.value !== filter_val){
|
50
|
+
add = false;
|
51
|
+
}
|
52
|
+
}
|
53
|
+
}
|
54
|
+
}
|
55
|
+
}
|
56
|
+
if(add)
|
57
|
+
rows[rows.length] = row;
|
58
|
+
} else {
|
59
|
+
rows[rows.length] = row;
|
60
|
+
}
|
61
|
+
|
62
|
+
};
|
63
|
+
send(JSON.stringify({'rows': rows, 'debug': debug}));
|
64
|
+
}"
|
65
|
+
|
66
|
+
|
67
|
+
class Tanker < ThingTank
|
68
|
+
design do
|
69
|
+
list :testlist, $list_filter # only when called with .all() / include_docs=true
|
70
|
+
#view :all_cars, :by => ['name']
|
71
|
+
character_view House, :by_name, :by => ['name']
|
72
|
+
character_view House, :by_special, :emit => "emit(doc.name, doc.project);"
|
73
|
+
character_view Car, :by_name, :by => ['name']
|
74
|
+
#character_view Car, :by_project, :emit => "emit(doc.project, 1);"
|
75
|
+
character_view Car, :by_project_and_name, :by => ['project', 'name']
|
76
|
+
|
77
|
+
character_view Car, :by_special, :map => "function(doc){ emit(doc.name, doc.project); }"
|
78
|
+
character_view Car, :by_special2, :map => "function(doc){ emit(doc.name, [doc.project, doc.name]); }"
|
79
|
+
character_view Car, :by_special3, :map => "function(doc){ emit(doc.name, [doc.name, doc.project]); }"
|
80
|
+
character_view Car, :by_special4, :emit => "emit(doc.name, [doc.name, doc.project]);"
|
81
|
+
character_view Car, :by_special5, :emit => "emit(doc.name, doc.project);"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
describe "with a car view" do
|
87
|
+
|
88
|
+
before do
|
89
|
+
reset_test_db!
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should be able to handle rows without docs" do
|
93
|
+
doc = Tanker.new {}
|
94
|
+
doc.as(Car) do |c|
|
95
|
+
c.project = 'a'
|
96
|
+
c.name = 'A'
|
97
|
+
end
|
98
|
+
doc.save
|
99
|
+
|
100
|
+
doc2 = Tanker.new {}
|
101
|
+
doc2.as(House) do |c|
|
102
|
+
c.project = 'b'
|
103
|
+
c.name = 'B'
|
104
|
+
end
|
105
|
+
doc2.save
|
106
|
+
|
107
|
+
doc3 = Tanker.new {}
|
108
|
+
doc3.as(House) do |c|
|
109
|
+
c.project = 'a'
|
110
|
+
c.name = 'House a1'
|
111
|
+
end
|
112
|
+
doc3.save
|
113
|
+
|
114
|
+
doc4 = Tanker.new {}
|
115
|
+
doc4.as(Car) do |c|
|
116
|
+
c.project = 'a'
|
117
|
+
c.name = 'A1'
|
118
|
+
end
|
119
|
+
doc4.save
|
120
|
+
|
121
|
+
doc5 = Tanker.new {}
|
122
|
+
doc5.as(Car) do |c|
|
123
|
+
c.project = 'a'
|
124
|
+
c.name = 'A3'
|
125
|
+
end
|
126
|
+
doc5.save
|
127
|
+
|
128
|
+
doc6 = Tanker.new {}
|
129
|
+
doc6.as(House) do |c|
|
130
|
+
c.project = 'b'
|
131
|
+
c.name = 'B2'
|
132
|
+
end
|
133
|
+
doc6.save
|
134
|
+
|
135
|
+
#assert_equal 3, Tanker.house_by_name.all().size
|
136
|
+
assert_equal 3, Tanker.car_by_project_and_name.rows().size
|
137
|
+
|
138
|
+
#assert_equal 4, Tanker.list_testlist('all', :list_filter => {'project' => 'a'}.to_json).all().size
|
139
|
+
#assert_equal 2, Tanker.list_testlist('all', :list_filter => {'project' => 'b'}.to_json).all().size
|
140
|
+
|
141
|
+
#result = Tanker.list_testlist('car_by_special', :list_filter => [['project', 'a']].to_json).execute()
|
142
|
+
#if result['error']
|
143
|
+
# p [:error_project_a, result['reason'].split("\n").first]
|
144
|
+
#else
|
145
|
+
# p [:debug_project_a, result['debug'], result['rows']]
|
146
|
+
#end
|
147
|
+
|
148
|
+
#p [:project_a, Tanker.list_testlist('car_by_special', :list_filter => [['project', 'a']].to_json).rows()]
|
149
|
+
|
150
|
+
# should check the correct value if the value isn't an array but already our filter
|
151
|
+
assert_equal 4, Tanker.list_testlist('car_by_special', :list_filter => [['project', 'a']].to_json).rows().size
|
152
|
+
# same for docs
|
153
|
+
assert_equal 4, Tanker.list_testlist('car_by_special', :list_filter => [['project', 'a']].to_json).all().size
|
154
|
+
|
155
|
+
# should check the correct index in the values array, if the index is the first one
|
156
|
+
assert_equal 4, Tanker.list_testlist('car_by_special2', :list_filter => [['project', 'a']].to_json).rows().size
|
157
|
+
# same for docs
|
158
|
+
assert_equal 4, Tanker.list_testlist('car_by_special2', :list_filter => [['project', 'a']].to_json).all().size
|
159
|
+
|
160
|
+
# should check for the correct index in the values array, skipping nil filters
|
161
|
+
assert_equal 4, Tanker.list_testlist('car_by_special3', :list_filter => [nil, ['project', 'a']].to_json).rows().size
|
162
|
+
# same for docs
|
163
|
+
assert_equal 4, Tanker.list_testlist('car_by_special3', :list_filter => [nil, ['project', 'a']].to_json).all().size
|
164
|
+
|
165
|
+
|
166
|
+
# should check for the correct index in the values array, skipping nil filters
|
167
|
+
assert_equal 3, Tanker.list_testlist('car_by_special4', :list_filter => [nil, ['project', 'a']].to_json).rows().size
|
168
|
+
# same for docs
|
169
|
+
assert_equal 3, Tanker.list_testlist('car_by_special4', :list_filter => [nil, ['project', 'a']].to_json).all().size
|
170
|
+
|
171
|
+
assert_equal 1, Tanker.list_testlist('house_by_special', :list_filter => [['project', 'a']].to_json).all().size
|
172
|
+
assert_equal 2, Tanker.list_testlist('house_by_special', :list_filter => [['project', 'b']].to_json).all().size
|
173
|
+
assert_equal 3, Tanker.list_testlist('car_by_special5', :list_filter => [['project', 'a']].to_json).rows().size
|
174
|
+
assert_equal 0, Tanker.list_testlist('car_by_special5', :list_filter => [['project', 'b']].to_json).all().size
|
175
|
+
|
176
|
+
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should be able to use character_views as well as normal views" do
|
180
|
+
doc = Tanker.new {}
|
181
|
+
doc.as(Car) do |c|
|
182
|
+
c.project = 'a'
|
183
|
+
c.name = 'A'
|
184
|
+
end
|
185
|
+
doc.save
|
186
|
+
|
187
|
+
doc2 = Tanker.new {}
|
188
|
+
doc2.as(House) do |c|
|
189
|
+
c.project = 'b'
|
190
|
+
c.name = 'B'
|
191
|
+
end
|
192
|
+
doc2.save
|
193
|
+
|
194
|
+
doc3 = Tanker.new {}
|
195
|
+
doc3.as(House) do |c|
|
196
|
+
c.project = 'a'
|
197
|
+
c.name = 'House a1'
|
198
|
+
end
|
199
|
+
doc3.save
|
200
|
+
|
201
|
+
doc4 = Tanker.new {}
|
202
|
+
doc4.as(Car) do |c|
|
203
|
+
c.project = 'a'
|
204
|
+
c.name = 'A1'
|
205
|
+
end
|
206
|
+
doc4.save
|
207
|
+
|
208
|
+
doc5 = Tanker.new {}
|
209
|
+
doc5.as(Car) do |c|
|
210
|
+
c.project = 'a'
|
211
|
+
c.name = 'A3'
|
212
|
+
end
|
213
|
+
doc5.save
|
214
|
+
|
215
|
+
doc6 = Tanker.new {}
|
216
|
+
doc6.as(House) do |c|
|
217
|
+
c.project = 'b'
|
218
|
+
c.name = 'B2'
|
219
|
+
end
|
220
|
+
doc6.save
|
221
|
+
|
222
|
+
assert_equal 3, Tanker.house_by_name.all().size
|
223
|
+
assert_equal 3, Tanker.car_by_name.all().size
|
224
|
+
|
225
|
+
assert_equal 4, Tanker.list_testlist('all', :list_filter => [['project', 'a']].to_json).all().size
|
226
|
+
assert_equal 2, Tanker.list_testlist('all', :list_filter => [['project', 'b']].to_json).all().size
|
227
|
+
|
228
|
+
#result = Tanker.list_testlist('house_by_name', :list_filter => {'project' => 'a'}.to_json, :include_docs => true).execute()
|
229
|
+
#if result['error']
|
230
|
+
# p [:error, result['reason'].split("\n").first]
|
231
|
+
#else
|
232
|
+
# p [:debug, result['debug']]
|
233
|
+
#end
|
234
|
+
|
235
|
+
assert_equal 1, Tanker.list_testlist('house_by_name', :list_filter => [['project', 'a']].to_json).all().size
|
236
|
+
assert_equal 2, Tanker.list_testlist('house_by_name', :list_filter => [['project', 'b']].to_json).all().size
|
237
|
+
assert_equal 3, Tanker.list_testlist('car_by_name', :list_filter => [['project', 'a']].to_json).all().size
|
238
|
+
assert_equal 0, Tanker.list_testlist('car_by_name', :list_filter => [['project', 'b']].to_json).all().size
|
239
|
+
|
240
|
+
end
|
241
|
+
|
242
|
+
it "should do something with the list" do
|
243
|
+
doc = Tanker.new {}
|
244
|
+
doc.as(Car) do |c|
|
245
|
+
c.project = 'a'
|
246
|
+
c.name = 'A'
|
247
|
+
end
|
248
|
+
doc.save
|
249
|
+
|
250
|
+
doc2 = Tanker.new {}
|
251
|
+
doc2.as(Car) do |c|
|
252
|
+
c.project = 'b'
|
253
|
+
c.name = 'B'
|
254
|
+
end
|
255
|
+
doc2.save
|
256
|
+
|
257
|
+
doc3 = Tanker.new {}
|
258
|
+
doc3.as(Car) do |c|
|
259
|
+
c.project = 'a'
|
260
|
+
c.name = 'a2'
|
261
|
+
end
|
262
|
+
doc3.save
|
263
|
+
|
264
|
+
|
265
|
+
#result = Tanker.list_testlist('all', :list_filter => {'project' => 'a'}.to_json, :include_docs => true).execute()
|
266
|
+
#if result['error']
|
267
|
+
# p [:error, result['reason'].split("\n").first]
|
268
|
+
#else
|
269
|
+
# p [:debug, result['debug']]
|
270
|
+
#end
|
271
|
+
assert_equal 3, Tanker.all.all().size
|
272
|
+
assert_equal 2, Tanker.list_testlist('all', :list_filter => [['project', 'a']].to_json).all().size
|
273
|
+
assert_equal 1, Tanker.list_testlist('all', :list_filter => [['project', 'b']].to_json).all().size
|
274
|
+
end
|
275
|
+
|
276
|
+
|
277
|
+
it "should have both without a filter list" do
|
278
|
+
doc = Tanker.new {}
|
279
|
+
doc.as(Car) do |c|
|
280
|
+
c.project = 'My Project'
|
281
|
+
c.name = 'My Name'
|
282
|
+
end
|
283
|
+
doc.save
|
284
|
+
|
285
|
+
doc2 = Tanker.new {}
|
286
|
+
doc2.as(Car) do |c|
|
287
|
+
c.project = 'Other Project'
|
288
|
+
c.name = 'My Name'
|
289
|
+
end
|
290
|
+
doc2.save
|
291
|
+
assert_equal 2, Tanker.all.all().size
|
292
|
+
assert_equal 2, Tanker.list_testlist('all').all().size
|
293
|
+
end
|
294
|
+
end
|
data/test/test_views.rb
CHANGED
@@ -21,6 +21,8 @@ class Tanker < ThingTank
|
|
21
21
|
character_view Car, :by_name, :by => ['name']
|
22
22
|
character_view House, :by_name, :by => ['name']
|
23
23
|
character_view Ship, :by_name, :by => ['name']
|
24
|
+
character_view Ship, :by_name_with_weight, :emit => 'emit(doc.name, doc.weight);'
|
25
|
+
character_view Ship, :by_name_with_weight2, :emit => 'emit(doc.name, [doc.name, doc.weight]);'
|
24
26
|
end
|
25
27
|
end
|
26
28
|
|
@@ -31,6 +33,29 @@ describe "with a car view" do
|
|
31
33
|
reset_test_db!
|
32
34
|
end
|
33
35
|
|
36
|
+
it "should get ships with name and weight as rows" do
|
37
|
+
ship = Tanker.create
|
38
|
+
ship.as(Ship) do |s|
|
39
|
+
s.name = "MS Dolphin"
|
40
|
+
s.weight = "1000 pound"
|
41
|
+
end
|
42
|
+
ship.save
|
43
|
+
|
44
|
+
result = Tanker.ship_by_name_with_weight.rows()
|
45
|
+
|
46
|
+
assert_equal 1, result.size
|
47
|
+
assert_equal 'MS Dolphin', result.first.key
|
48
|
+
assert_equal '1000 pound', result.first.value
|
49
|
+
|
50
|
+
result = Tanker.ship_by_name_with_weight2.rows()
|
51
|
+
|
52
|
+
assert_equal 1, result.size
|
53
|
+
assert_equal 'MS Dolphin', result.first.key
|
54
|
+
assert_equal 'MS Dolphin', result.first.value.first
|
55
|
+
assert_equal '1000 pound', result.first.value.last
|
56
|
+
|
57
|
+
end
|
58
|
+
|
34
59
|
it "should get all cars" do
|
35
60
|
car1 = Tanker.create
|
36
61
|
car1.as(Car) do |c|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: thingtank
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-02-
|
12
|
+
date: 2012-02-15 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: json
|
16
|
-
requirement: &
|
16
|
+
requirement: &14082040 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *14082040
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: couchrest
|
27
|
-
requirement: &
|
27
|
+
requirement: &14080680 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *14080680
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: couchrest_model
|
38
|
-
requirement: &
|
38
|
+
requirement: &14079940 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,21 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *14079940
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: defined
|
49
|
+
requirement: &14079100 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *14079100
|
47
58
|
- !ruby/object:Gem::Dependency
|
48
59
|
name: guard
|
49
|
-
requirement: &
|
60
|
+
requirement: &14078280 !ruby/object:Gem::Requirement
|
50
61
|
none: false
|
51
62
|
requirements:
|
52
63
|
- - ! '>='
|
@@ -54,10 +65,10 @@ dependencies:
|
|
54
65
|
version: '0'
|
55
66
|
type: :development
|
56
67
|
prerelease: false
|
57
|
-
version_requirements: *
|
68
|
+
version_requirements: *14078280
|
58
69
|
- !ruby/object:Gem::Dependency
|
59
70
|
name: libnotify
|
60
|
-
requirement: &
|
71
|
+
requirement: &14060560 !ruby/object:Gem::Requirement
|
61
72
|
none: false
|
62
73
|
requirements:
|
63
74
|
- - ! '>='
|
@@ -65,10 +76,10 @@ dependencies:
|
|
65
76
|
version: '0'
|
66
77
|
type: :development
|
67
78
|
prerelease: false
|
68
|
-
version_requirements: *
|
79
|
+
version_requirements: *14060560
|
69
80
|
- !ruby/object:Gem::Dependency
|
70
81
|
name: rb-inotify
|
71
|
-
requirement: &
|
82
|
+
requirement: &14059820 !ruby/object:Gem::Requirement
|
72
83
|
none: false
|
73
84
|
requirements:
|
74
85
|
- - ! '>='
|
@@ -76,10 +87,10 @@ dependencies:
|
|
76
87
|
version: '0'
|
77
88
|
type: :development
|
78
89
|
prerelease: false
|
79
|
-
version_requirements: *
|
90
|
+
version_requirements: *14059820
|
80
91
|
- !ruby/object:Gem::Dependency
|
81
92
|
name: guard-minitest
|
82
|
-
requirement: &
|
93
|
+
requirement: &14059120 !ruby/object:Gem::Requirement
|
83
94
|
none: false
|
84
95
|
requirements:
|
85
96
|
- - ! '>='
|
@@ -87,10 +98,10 @@ dependencies:
|
|
87
98
|
version: '0'
|
88
99
|
type: :development
|
89
100
|
prerelease: false
|
90
|
-
version_requirements: *
|
101
|
+
version_requirements: *14059120
|
91
102
|
- !ruby/object:Gem::Dependency
|
92
103
|
name: linecache19
|
93
|
-
requirement: &
|
104
|
+
requirement: &14058400 !ruby/object:Gem::Requirement
|
94
105
|
none: false
|
95
106
|
requirements:
|
96
107
|
- - ! '>='
|
@@ -98,10 +109,10 @@ dependencies:
|
|
98
109
|
version: '0'
|
99
110
|
type: :development
|
100
111
|
prerelease: false
|
101
|
-
version_requirements: *
|
112
|
+
version_requirements: *14058400
|
102
113
|
- !ruby/object:Gem::Dependency
|
103
114
|
name: ruby-debug19
|
104
|
-
requirement: &
|
115
|
+
requirement: &14057840 !ruby/object:Gem::Requirement
|
105
116
|
none: false
|
106
117
|
requirements:
|
107
118
|
- - ! '>='
|
@@ -109,10 +120,10 @@ dependencies:
|
|
109
120
|
version: '0'
|
110
121
|
type: :development
|
111
122
|
prerelease: false
|
112
|
-
version_requirements: *
|
123
|
+
version_requirements: *14057840
|
113
124
|
- !ruby/object:Gem::Dependency
|
114
125
|
name: yard
|
115
|
-
requirement: &
|
126
|
+
requirement: &14057060 !ruby/object:Gem::Requirement
|
116
127
|
none: false
|
117
128
|
requirements:
|
118
129
|
- - ~>
|
@@ -120,10 +131,10 @@ dependencies:
|
|
120
131
|
version: 0.6.0
|
121
132
|
type: :development
|
122
133
|
prerelease: false
|
123
|
-
version_requirements: *
|
134
|
+
version_requirements: *14057060
|
124
135
|
- !ruby/object:Gem::Dependency
|
125
136
|
name: bundler
|
126
|
-
requirement: &
|
137
|
+
requirement: &14056420 !ruby/object:Gem::Requirement
|
127
138
|
none: false
|
128
139
|
requirements:
|
129
140
|
- - ~>
|
@@ -131,10 +142,10 @@ dependencies:
|
|
131
142
|
version: 1.0.0
|
132
143
|
type: :development
|
133
144
|
prerelease: false
|
134
|
-
version_requirements: *
|
145
|
+
version_requirements: *14056420
|
135
146
|
- !ruby/object:Gem::Dependency
|
136
147
|
name: jeweler
|
137
|
-
requirement: &
|
148
|
+
requirement: &14055640 !ruby/object:Gem::Requirement
|
138
149
|
none: false
|
139
150
|
requirements:
|
140
151
|
- - ~>
|
@@ -142,7 +153,7 @@ dependencies:
|
|
142
153
|
version: 1.6.4
|
143
154
|
type: :development
|
144
155
|
prerelease: false
|
145
|
-
version_requirements: *
|
156
|
+
version_requirements: *14055640
|
146
157
|
description:
|
147
158
|
email: ! 'Base64.decode64(bGludXhAbWFyY3JlbmVhcm5zLmRl
|
148
159
|
|
@@ -166,6 +177,7 @@ files:
|
|
166
177
|
- examples/immortal_julius.rb
|
167
178
|
- examples/marriage_improvement.rb
|
168
179
|
- examples/second_marriage.rb
|
180
|
+
- lib/couchrest/extensions/list.rb
|
169
181
|
- lib/couchrest/extensions/view.rb
|
170
182
|
- lib/thingtank.rb
|
171
183
|
- lib/thingtank/callbacks.rb
|
@@ -185,6 +197,7 @@ files:
|
|
185
197
|
- test/examples/test_second_marriage.rb
|
186
198
|
- test/test_fakebase.rb
|
187
199
|
- test/test_helper.rb
|
200
|
+
- test/test_lists.rb
|
188
201
|
- test/test_thingtank.rb
|
189
202
|
- test/test_views.rb
|
190
203
|
homepage: http://github.com/metakeule/thingtank
|
@@ -202,7 +215,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
202
215
|
version: '0'
|
203
216
|
segments:
|
204
217
|
- 0
|
205
|
-
hash:
|
218
|
+
hash: 683834457971254246
|
206
219
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
207
220
|
none: false
|
208
221
|
requirements:
|
@@ -214,5 +227,5 @@ rubyforge_project:
|
|
214
227
|
rubygems_version: 1.8.15
|
215
228
|
signing_key:
|
216
229
|
specification_version: 3
|
217
|
-
summary:
|
230
|
+
summary: couchrest docs with multiple characters
|
218
231
|
test_files: []
|