populate-me 0.0.33 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +1 -0
- data/LICENSE +1 -1
- data/README.md +399 -4
- data/Rakefile +14 -0
- data/example/config.ru +67 -0
- data/lib/populate_me.rb +2 -0
- data/lib/populate_me/admin.rb +143 -0
- data/lib/populate_me/admin/__assets__/css/main.css +174 -0
- data/lib/populate_me/admin/__assets__/js/columnav.js +82 -0
- data/lib/populate_me/admin/__assets__/js/main.js +251 -0
- data/lib/populate_me/admin/__assets__/js/mustache.js +578 -0
- data/lib/populate_me/admin/__assets__/js/sortable.js +2 -0
- data/lib/populate_me/admin/views/page.erb +163 -0
- data/lib/populate_me/api.rb +124 -0
- data/lib/populate_me/attachment.rb +182 -0
- data/lib/populate_me/document.rb +178 -0
- data/lib/populate_me/document_mixins/admin_adapter.rb +131 -0
- data/lib/populate_me/document_mixins/callbacks.rb +104 -0
- data/lib/populate_me/document_mixins/outcasting.rb +49 -0
- data/lib/populate_me/document_mixins/persistence.rb +92 -0
- data/lib/populate_me/document_mixins/schema.rb +99 -0
- data/lib/populate_me/document_mixins/typecasting.rb +60 -0
- data/lib/populate_me/document_mixins/validation.rb +44 -0
- data/lib/populate_me/file_system_attachment.rb +40 -0
- data/lib/populate_me/grid_fs_attachment.rb +127 -0
- data/lib/populate_me/mongo.rb +98 -3
- data/lib/populate_me/variation.rb +34 -0
- data/lib/populate_me/version.rb +4 -0
- data/populate-me.gemspec +20 -12
- data/test/helper.rb +37 -0
- data/test/test_admin.rb +161 -0
- data/test/test_api.rb +246 -0
- data/test/test_attachment.rb +155 -0
- data/test/test_document.rb +120 -0
- data/test/test_document_admin_adapter.rb +43 -0
- data/test/test_document_callbacks.rb +107 -0
- data/test/test_document_persistence.rb +56 -0
- data/test/test_document_typecasting.rb +121 -0
- data/test/test_mongo.rb +217 -0
- data/test/test_variation.rb +91 -0
- data/test/test_version.rb +11 -0
- metadata +115 -66
- data/lib/populate_me/control.rb +0 -196
- data/lib/populate_me/control/_public/css/main.css +0 -207
- data/lib/populate_me/control/_public/css/plugin.asmselect.css +0 -63
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-bg_flat_30_cccccc_40x100.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-bg_flat_50_5c5c5c_40x100.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-bg_glass_20_555555_1x400.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-bg_glass_40_0078a3_1x400.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-bg_glass_40_ffc73d_1x400.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-bg_gloss-wave_25_333333_500x100.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-bg_highlight-soft_80_eeeeee_1x100.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-bg_inset-soft_25_000000_1x100.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-bg_inset-soft_30_f58400_1x100.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-icons_222222_256x240.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-icons_4b8e0b_256x240.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-icons_a83300_256x240.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-icons_cccccc_256x240.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-icons_ffffff_256x240.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/jquery-ui-1.8.17.custom.css +0 -430
- data/lib/populate_me/control/_public/img/grip.png +0 -0
- data/lib/populate_me/control/_public/img/icons-cms-solarized.png +0 -0
- data/lib/populate_me/control/_public/img/icons-cms.png +0 -0
- data/lib/populate_me/control/_public/img/placeholder.png +0 -0
- data/lib/populate_me/control/_public/img/placeholder.stash_thumb.gif +0 -0
- data/lib/populate_me/control/_public/img/placeholder.stash_thumb.png +0 -0
- data/lib/populate_me/control/_public/img/small-loader.gif +0 -0
- data/lib/populate_me/control/_public/js/addon.timepicker.js +0 -20
- data/lib/populate_me/control/_public/js/jquery-ui.js +0 -114
- data/lib/populate_me/control/_public/js/jquery.js +0 -167
- data/lib/populate_me/control/_public/js/jquery.mustache.js +0 -559
- data/lib/populate_me/control/_public/js/main.js +0 -144
- data/lib/populate_me/control/_public/js/plugin.asmselect.js +0 -407
- data/lib/populate_me/control/_public/js/plugin.form.js +0 -11
- data/lib/populate_me/control/_public/js/plugin.quicksearch.js +0 -1
- data/lib/populate_me/control/_public/js/plugin.underwood.js +0 -4
- data/lib/populate_me/control/views/populate_me_layout.erb +0 -75
- data/lib/populate_me/ext.rb +0 -16
- data/lib/populate_me/mongo/backend_api_plug.rb +0 -78
- data/lib/populate_me/mongo/crushyform.rb +0 -243
- data/lib/populate_me/mongo/mutation.rb +0 -324
- data/lib/populate_me/mongo/plug.rb +0 -134
- data/lib/populate_me/mongo/stash.rb +0 -171
- data/test/spec_ext.rb +0 -29
- data/test/spec_mongo_mutation.rb +0 -279
@@ -1,134 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require 'populate_me/mongo/mutation'
|
4
|
-
require 'populate_me/mongo/stash'
|
5
|
-
require 'populate_me/mongo/crushyform'
|
6
|
-
require 'populate_me/mongo/backend_api_plug'
|
7
|
-
|
8
|
-
module PopulateMe
|
9
|
-
module Mongo
|
10
|
-
module Plug
|
11
|
-
|
12
|
-
# This module is the one that plugs the model to the CMS
|
13
|
-
|
14
|
-
def self.included(base)
|
15
|
-
base.class_eval do
|
16
|
-
include PopulateMe::Mongo::Mutation
|
17
|
-
include PopulateMe::Mongo::Stash if (base.const_defined?(:WITH_STASH) && base::WITH_STASH)
|
18
|
-
include PopulateMe::Mongo::BackendApiPlug
|
19
|
-
include PopulateMe::Mongo::Crushyform
|
20
|
-
include InstanceMethods
|
21
|
-
end
|
22
|
-
base.extend(ClassMethods)
|
23
|
-
base.populate_config = {:nut_tree_class=>'sortable-grid'}
|
24
|
-
end
|
25
|
-
|
26
|
-
module ClassMethods
|
27
|
-
|
28
|
-
attr_accessor :populate_config
|
29
|
-
|
30
|
-
# def list_view(r)
|
31
|
-
# @list_options = {:request=>r, :destination=>r.fullpath, :path=>r.script_name, :filter=>r['filter'] }
|
32
|
-
# @list_options.store(:sortable,sortable_on_that_page?)
|
33
|
-
# out = list_view_header
|
34
|
-
# out << many_to_many_picker unless populate_config[:minilist_class].nil?
|
35
|
-
# out << "<ul class='nut-tree #{'sortable' if @list_options[:sortable]} #{populate_config[:nut_tree_class]}' id='#{self.name}' rel='#{@list_options[:path]}/#{self.name}'>"
|
36
|
-
# self.find(@list_options[:filter]||{}).each {|m| out << m.to_nutshell }
|
37
|
-
# out << "</ul>"
|
38
|
-
# end
|
39
|
-
|
40
|
-
def sortable_on_that_page?(r)
|
41
|
-
@schema.key?('position') && (@schema['position'][:scope].nil? || (r['filter']||{}).key?(@schema['position'][:scope]))
|
42
|
-
end
|
43
|
-
|
44
|
-
# def minilist_view
|
45
|
-
# o = "<ul class='minilist'>\n"
|
46
|
-
# self.collection.find.each_mutant do |m|
|
47
|
-
# thumb = m.respond_to?(:to_populate_thumb) ? m.to_populate_thumb('stash_thumb_gif') : m.placeholder_thumb('stash_thumb_gif')
|
48
|
-
# o << "<li title='#{m.to_label}' id='mini-#{m.id}'>#{thumb}<div>#{m.to_label}</div></li>\n"
|
49
|
-
# end
|
50
|
-
# o << "</ul>\n"
|
51
|
-
# end
|
52
|
-
|
53
|
-
private
|
54
|
-
|
55
|
-
def image_slot(name='image',opts={})
|
56
|
-
super(name,opts)
|
57
|
-
# First image slot is considered the best populate thumb by default
|
58
|
-
unless instance_methods.include?(:to_populate_thumb)
|
59
|
-
define_method :to_populate_thumb do |style|
|
60
|
-
generic_thumb(name, style)
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
end
|
66
|
-
|
67
|
-
module InstanceMethods
|
68
|
-
|
69
|
-
def after_stash(col)
|
70
|
-
convert(col, "-resize '100x75^' -gravity center -extent 100x75", 'stash_thumb_gif')
|
71
|
-
end
|
72
|
-
|
73
|
-
def generic_thumb(img , size='stash_thumb_gif', obj=self)
|
74
|
-
return placeholder_thumb(size) if obj.nil?
|
75
|
-
current = obj.doc[img]
|
76
|
-
if !current.nil? && !current[size].nil?
|
77
|
-
"/gridfs/#{current[size]}"
|
78
|
-
else
|
79
|
-
placeholder_thumb(size)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
def placeholder_thumb(size)
|
84
|
-
"/_public/img/placeholder.#{size.gsub(/^(.*)_([a-zA-Z]+)$/, '\1.\2')}"
|
85
|
-
end
|
86
|
-
|
87
|
-
def to_nutshell
|
88
|
-
{
|
89
|
-
'class_name'=>model.name,
|
90
|
-
'id'=>@doc['_id'].to_s,
|
91
|
-
'foreign_key_name'=>model.foreign_key_name,
|
92
|
-
'title'=>self.to_label,
|
93
|
-
'thumb'=>self.respond_to?(:to_populate_thumb) ? self.to_populate_thumb('stash_thumb_gif') : nil,
|
94
|
-
'children'=>nutshell_children,
|
95
|
-
}
|
96
|
-
end
|
97
|
-
|
98
|
-
def in_nutshell
|
99
|
-
o = model.list_options
|
100
|
-
out = "<div class='in-nutshell'>\n"
|
101
|
-
out << self.to_populate_thumb('nutshell_jpg') if self.respond_to?(:to_populate_thumb)
|
102
|
-
cols = model.populate_config[:quick_update_fields] || nutshell_backend_columns.select{|col|
|
103
|
-
[:boolean,:select].include?(model.schema[col][:type]) && !model.schema[col][:multiple] && !model.schema[col][:no_quick_update]
|
104
|
-
}
|
105
|
-
cols.each do |c|
|
106
|
-
column_label = c.to_s.sub(/^id_/, '').tr('_', ' ').capitalize
|
107
|
-
out << "<div class='quick-update'><form><span class='column-title'>#{column_label}:</span> #{self.crushyinput(c)}</form></div>\n"
|
108
|
-
end
|
109
|
-
out << "</div>\n"
|
110
|
-
end
|
111
|
-
|
112
|
-
def nutshell_backend_associations
|
113
|
-
model.relationships
|
114
|
-
end
|
115
|
-
|
116
|
-
def nutshell_children
|
117
|
-
nutshell_backend_associations.inject([]) do |arr, (k, opts)|
|
118
|
-
unless opts[:hidden]
|
119
|
-
klass = Kernel.const_get(k)
|
120
|
-
arr << {
|
121
|
-
'children_class_name'=>k,
|
122
|
-
'title'=>opts[:link_text] || "#{klass.human_name}(s)",
|
123
|
-
'count'=>self.children_count(klass),
|
124
|
-
}
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
end
|
130
|
-
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
@@ -1,171 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
module PopulateMe
|
3
|
-
module Mongo
|
4
|
-
module Stash
|
5
|
-
|
6
|
-
# This module gives models the ability to deal with attachments
|
7
|
-
|
8
|
-
def self.included(base)
|
9
|
-
Stash.classes << base
|
10
|
-
base.extend(ClassMethods)
|
11
|
-
base.gridfs = GRID
|
12
|
-
end
|
13
|
-
|
14
|
-
module ClassMethods
|
15
|
-
attr_accessor :gridfs
|
16
|
-
def all_after_stash
|
17
|
-
self.collection.find.each do |i|
|
18
|
-
self.schema.each do |k,v|
|
19
|
-
obj = self.new(i)
|
20
|
-
obj.after_stash(k) if v[:type]==:attachment&&obj[k].to_s!=''
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
# Instance Methods
|
27
|
-
|
28
|
-
def build_image_tag(col='image', style='original', html_attributes={})
|
29
|
-
return '' if @doc[col].nil?||@doc[col][style].nil?
|
30
|
-
title_field, alt_field = col+'_tooltip', col+'_alternative_text'
|
31
|
-
title = @doc[title_field] if model.schema.keys.include?(title_field)
|
32
|
-
alt = @doc[alt_field] if model.schema.keys.include?(alt_field)
|
33
|
-
html_attributes = {:src => "/gridfs/#{@doc[col][style]}", :title => title, :alt => alt}.update(html_attributes)
|
34
|
-
html_attributes = html_attributes.map do |k,v|
|
35
|
-
%{#{k}="#{model.html_escape(v.to_s)}"}
|
36
|
-
end.join(' ')
|
37
|
-
"<img #{html_attributes} />"
|
38
|
-
end
|
39
|
-
|
40
|
-
def fix_type_attachment(k,v)
|
41
|
-
if v=='nil'
|
42
|
-
delete_files_for(k) unless new?
|
43
|
-
@doc[k] = nil
|
44
|
-
elsif v.is_a?(Hash)&&v.key?(:tempfile)
|
45
|
-
delete_files_for(k) unless new?
|
46
|
-
@temp_attachments ||= {}
|
47
|
-
@temp_attachments[k] = v
|
48
|
-
attachment_id = model.gridfs.upload_from_stream(
|
49
|
-
v[:filename],
|
50
|
-
v[:tempfile], {
|
51
|
-
:content_type=>v[:type]
|
52
|
-
})
|
53
|
-
@doc[k] = {'original'=>attachment_id}
|
54
|
-
else # Untouched
|
55
|
-
@doc[k] = @old_doc[k]
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def delete_files_for(col)
|
60
|
-
obj = (@old_doc||@doc)[col]
|
61
|
-
if obj.respond_to?(:each)
|
62
|
-
obj.each do |k,v|
|
63
|
-
gridfile = model.gridfs.find(_id: v).first
|
64
|
-
model.gridfs.delete(v) unless gridfile.nil?
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def after_delete
|
70
|
-
super
|
71
|
-
model.schema.each do |k,v|
|
72
|
-
delete_files_for(k) if v[:type]==:attachment
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
def after_save
|
77
|
-
super
|
78
|
-
unless @temp_attachments.nil?
|
79
|
-
@temp_attachments.each do |k,v|
|
80
|
-
after_stash(k)
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
def after_stash(col); end
|
86
|
-
|
87
|
-
def convert(col, convert_steps, style)
|
88
|
-
return if @doc[col].nil?
|
89
|
-
if @temp_attachments.nil? || @temp_attachments[col].nil?
|
90
|
-
f = model.gridfs.find({'_id'=>@doc[col]['original']}).first
|
91
|
-
return if f.nil?
|
92
|
-
src = Tempfile.new('MongoStash_src')
|
93
|
-
src.binmode
|
94
|
-
model.gridfs.download_to_stream(@doc[col]['original'], src)
|
95
|
-
return unless f['contentType'].to_s[/^image\//]
|
96
|
-
src.close
|
97
|
-
@temp_attachments ||= {}
|
98
|
-
@temp_attachments[col] ||= {}
|
99
|
-
@temp_attachments[col][:tempfile] = src
|
100
|
-
@temp_attachments[col][:type] = f['contentType']
|
101
|
-
else
|
102
|
-
return unless @temp_attachments[col][:type][/^image\//]
|
103
|
-
src = @temp_attachments[col][:tempfile]
|
104
|
-
end
|
105
|
-
model.gridfs.delete(@doc[col][style]) unless @doc[col][style].nil?
|
106
|
-
ext = style[/[a-zA-Z]+$/].insert(0,'.')
|
107
|
-
content_type = Rack::Mime.mime_type(ext)
|
108
|
-
unless content_type[/^image\//]
|
109
|
-
ext = '.jpg'
|
110
|
-
content_type = 'image/jpeg'
|
111
|
-
end
|
112
|
-
dest = Tempfile.new(['MongoStash_dest', ext])
|
113
|
-
dest.binmode
|
114
|
-
dest.close
|
115
|
-
system "convert \"#{src.path}\" #{convert_steps} \"#{dest.path}\""
|
116
|
-
filename = "#{model.name}/#{self.id}/#{style}"
|
117
|
-
attachment_id = model.gridfs.upload_from_stream(
|
118
|
-
filename,
|
119
|
-
dest.open,
|
120
|
-
{:content_type=>content_type}
|
121
|
-
)
|
122
|
-
@doc[col] = @doc[col].update({style=>attachment_id})
|
123
|
-
model.collection.update_one({'_id'=>@doc['_id']}, @doc)
|
124
|
-
#src.close!
|
125
|
-
dest.close!
|
126
|
-
end
|
127
|
-
|
128
|
-
class << self
|
129
|
-
attr_accessor :classes
|
130
|
-
Stash.classes = []
|
131
|
-
|
132
|
-
def all_after_stash
|
133
|
-
Stash.classes.each do |m|
|
134
|
-
m.all_after_stash
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
def fix_dots_in_keys(c, for_real=false)
|
139
|
-
puts "\n#{c}" unless for_real
|
140
|
-
img_keys = c.schema.select{|k,v| v[:type]==:attachment }.keys
|
141
|
-
c.find({}, {:fields=>img_keys}).each do |e|
|
142
|
-
old_hash = e.doc.select{|k,v| img_keys.include?(k) }
|
143
|
-
fixed_hash = Marshal.load(Marshal.dump(old_hash))
|
144
|
-
img_keys.each do |k|
|
145
|
-
(fixed_hash[k]||{}).keys.each do |style|
|
146
|
-
fixed_hash[k][style.tr('.','_')] = fixed_hash[k].delete(style)
|
147
|
-
end
|
148
|
-
end
|
149
|
-
next if old_hash==fixed_hash
|
150
|
-
|
151
|
-
if for_real
|
152
|
-
c.collection.update_one({'_id'=>e.id}, {'$set'=>fixed_hash})
|
153
|
-
else
|
154
|
-
puts old_hash.inspect
|
155
|
-
puts fixed_hash.inspect
|
156
|
-
end
|
157
|
-
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
def all_fix_dots_in_keys(for_real=false)
|
162
|
-
Stash.classes.each do |c|
|
163
|
-
Stash.fix_dots_in_keys(c, for_real)
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
end
|
168
|
-
|
169
|
-
end
|
170
|
-
end
|
171
|
-
end
|
data/test/spec_ext.rb
DELETED
@@ -1,29 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
Encoding.default_internal = Encoding.default_external = Encoding::UTF_8 if RUBY_VERSION >= '1.9.0'
|
3
|
-
|
4
|
-
require 'rubygems'
|
5
|
-
require 'bacon'
|
6
|
-
$:.unshift './lib'
|
7
|
-
require "populate_me/ext"
|
8
|
-
|
9
|
-
describe 'Integer' do
|
10
|
-
describe '#to_price_string' do
|
11
|
-
should 'Display numbers correctly' do
|
12
|
-
4595.to_price_string.should=='45.95'
|
13
|
-
7000.to_price_string.should=='70'
|
14
|
-
1234567890.to_price_string.should=='12,345,678.90'
|
15
|
-
-140000.to_price_string.should=='-1,400'
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
describe 'String' do
|
21
|
-
describe '#to_price_integer' do
|
22
|
-
should 'Parse numbers correctly' do
|
23
|
-
'28'.to_price_integer.should==2800
|
24
|
-
'45.95'.to_price_integer.should==4595
|
25
|
-
' £-12,345,678.90 '.to_price_integer.should==-1234567890
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
data/test/spec_mongo_mutation.rb
DELETED
@@ -1,279 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
Encoding.default_internal = Encoding.default_external = Encoding::UTF_8 if RUBY_VERSION >= '1.9.0'
|
3
|
-
|
4
|
-
require 'rubygems'
|
5
|
-
require 'bacon'
|
6
|
-
require 'mongo'
|
7
|
-
require 'rack/utils'
|
8
|
-
$:.unshift './lib'
|
9
|
-
require 'populate_me/mongo'
|
10
|
-
|
11
|
-
MONGO = Mongo::Client.new([ '127.0.0.1:27017' ], :database => 'test-mongo-mutation')
|
12
|
-
class NoDB
|
13
|
-
include PopulateMe::Mongo::Plug
|
14
|
-
def self.human_name; 'No DB'; end
|
15
|
-
end
|
16
|
-
DB = MONGO.database
|
17
|
-
|
18
|
-
class Naked; include PopulateMe::Mongo::Plug; end
|
19
|
-
|
20
|
-
class Person
|
21
|
-
include PopulateMe::Mongo::Plug
|
22
|
-
slot "name" # no options
|
23
|
-
slot "surname"
|
24
|
-
slot "age", :type=>:integer, :default=>18
|
25
|
-
image_slot "portrait"
|
26
|
-
slot 'subscribed_on', :type=>:date, :default=>proc{Time.now}
|
27
|
-
end
|
28
|
-
|
29
|
-
class Address
|
30
|
-
include PopulateMe::Mongo::Plug
|
31
|
-
slot "body"
|
32
|
-
end
|
33
|
-
|
34
|
-
class Article
|
35
|
-
include PopulateMe::Mongo::Plug
|
36
|
-
slot 'title'
|
37
|
-
slot 'content', :type=>:text
|
38
|
-
image_slot
|
39
|
-
end
|
40
|
-
|
41
|
-
class FeatureBox
|
42
|
-
include PopulateMe::Mongo::Plug
|
43
|
-
slot 'header'
|
44
|
-
self.label_column = 'header'
|
45
|
-
def self.human_plural_name; 'Feature Boxes'; end
|
46
|
-
end
|
47
|
-
|
48
|
-
describe "PopulateMe::Mongo::Mutation" do
|
49
|
-
|
50
|
-
describe ".db" do
|
51
|
-
it "Should be set to DB constant by default" do
|
52
|
-
NoDB.db.should==nil
|
53
|
-
Naked.db.should==DB
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
shared "Empty Hash" do
|
58
|
-
it "Should be set to an empty hash by default" do
|
59
|
-
@bson.class.should==Hash
|
60
|
-
@bson.empty?.should==true
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
describe ".schema" do
|
65
|
-
before { @bson = Naked.schema }
|
66
|
-
behaves_like "Empty Hash"
|
67
|
-
end
|
68
|
-
|
69
|
-
describe ".relationships" do
|
70
|
-
before { @bson = Naked.relationships }
|
71
|
-
behaves_like "Empty Hash"
|
72
|
-
end
|
73
|
-
|
74
|
-
describe ".human_name" do
|
75
|
-
it "Returns a legible version of the class name - override when incorrect" do
|
76
|
-
Article.human_name.should=='Article'
|
77
|
-
FeatureBox.human_name.should=='Feature Box'
|
78
|
-
# No accronym for simplicity
|
79
|
-
# Easier to override when needed
|
80
|
-
NoDB.human_name.should=='No DB'
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
describe ".human_plural_name" do
|
85
|
-
it "Only adds an 's' to human name - override if needed" do
|
86
|
-
Article.human_plural_name.should=='Articles'
|
87
|
-
# No rules for simplicity
|
88
|
-
# Easier to override when needed
|
89
|
-
FeatureBox.human_plural_name.should=='Feature Boxes'
|
90
|
-
# Here only .human_name was overridden
|
91
|
-
NoDB.human_plural_name.should=='No DBs'
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
describe ".ref" do
|
96
|
-
it 'Returns a selector for a BSON::ObjectId' do
|
97
|
-
id = BSON::ObjectId.new
|
98
|
-
Address.ref(id).should=={'_id'=>id}
|
99
|
-
end
|
100
|
-
it 'Makes the argument a BSON::ObjectId if it is a valid string' do
|
101
|
-
string_id = '000000000000000000000000'
|
102
|
-
BSON::ObjectId.legal?(string_id).should==true
|
103
|
-
Address.ref(string_id).should=={'_id'=>BSON::ObjectId.from_string(string_id)}
|
104
|
-
end
|
105
|
-
it 'Makes a selector for multiple docs if argument is an Array' do
|
106
|
-
Address.ref([]).should=={'_id'=>{'$in'=>[]}}
|
107
|
-
id = BSON::ObjectId.new
|
108
|
-
string_id = '000000000000000000000000'
|
109
|
-
Address.ref([id,string_id]).should=={'_id'=>{'$in'=>[id,BSON::ObjectId.from_string(string_id)]}}
|
110
|
-
end
|
111
|
-
it 'Just put an empty string in selector for any invalid argument' do
|
112
|
-
Address.ref('abc').should=={'_id'=>''}
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
shared "Basic slot" do
|
117
|
-
it "Adds the declared slot to the schema" do
|
118
|
-
@klass.schema.key?(@key).should==true
|
119
|
-
end
|
120
|
-
it "Defines getters and setters" do
|
121
|
-
@klass.new.respond_to?(@key).should==true
|
122
|
-
@klass.new.respond_to?(@key+'=').should==true
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
describe ".slot" do
|
127
|
-
before { @klass = Person; @key = 'age' }
|
128
|
-
behaves_like "Basic slot"
|
129
|
-
it "Keeps the options in schema" do
|
130
|
-
Person.schema['age'][:default].should==18
|
131
|
-
Person.schema['age'][:type].should==:integer
|
132
|
-
end
|
133
|
-
it "Sets :type option to :string by default if not provided" do
|
134
|
-
Person.schema['name'][:type].should==:string
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
shared "Correctly typed" do
|
139
|
-
it "Has the correct type" do
|
140
|
-
@klass.schema[@key][:type].should==@type
|
141
|
-
end
|
142
|
-
end
|
143
|
-
|
144
|
-
shared "Image slot" do
|
145
|
-
describe "Reference slot" do
|
146
|
-
before { @type = :attachment }
|
147
|
-
behaves_like "Basic slot"
|
148
|
-
behaves_like "Correctly typed"
|
149
|
-
end
|
150
|
-
describe "Tooltip slot" do
|
151
|
-
before { @key = @key+'_tooltip'; @type = :string }
|
152
|
-
behaves_like "Basic slot"
|
153
|
-
behaves_like "Correctly typed"
|
154
|
-
end
|
155
|
-
describe "Alt text slot" do
|
156
|
-
before { @key = @key+'_alternative_text'; @type = :string }
|
157
|
-
behaves_like "Basic slot"
|
158
|
-
behaves_like "Correctly typed"
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
describe ".image_slot" do
|
163
|
-
describe "Name provided" do
|
164
|
-
before { @klass = Person; @key = 'portrait' }
|
165
|
-
behaves_like "Image slot"
|
166
|
-
end
|
167
|
-
describe "Name not provided" do
|
168
|
-
before { @klass = Article; @key = 'image' }
|
169
|
-
behaves_like "Image slot"
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
|
-
# .slug_column
|
174
|
-
# .foreign_key_name
|
175
|
-
# .collection
|
176
|
-
# .find
|
177
|
-
# .find_one
|
178
|
-
# .count
|
179
|
-
# .sorting_order
|
180
|
-
# .sort
|
181
|
-
# .get
|
182
|
-
# .delete
|
183
|
-
# .is_unique
|
184
|
-
# .has_many
|
185
|
-
|
186
|
-
shared "Has error recipient" do
|
187
|
-
it "Has an empty recipent for errors" do
|
188
|
-
@inst.errors.should=={}
|
189
|
-
end
|
190
|
-
end
|
191
|
-
|
192
|
-
describe "#initialize" do
|
193
|
-
describe "With fields" do
|
194
|
-
before { @inst = Person.new({'age'=>42, 'name'=>'Bozo', 'car'=>'Jaguar'}) }
|
195
|
-
it "Should be flagged as new if the doc has no _id yet" do
|
196
|
-
@inst.new?.should==true
|
197
|
-
end
|
198
|
-
it "Should not be flagged as new if the doc has an _id" do
|
199
|
-
@inst['_id'] = 'abc'
|
200
|
-
@inst.new?.should==false
|
201
|
-
end
|
202
|
-
it "Should pass all keys to the doc" do
|
203
|
-
@inst['name'].should=='Bozo'
|
204
|
-
@inst['car'].should=='Jaguar'
|
205
|
-
end
|
206
|
-
behaves_like "Has error recipient"
|
207
|
-
end
|
208
|
-
describe "Fresh new one" do
|
209
|
-
before { @inst = Person.new }
|
210
|
-
it "Should be flagged as new" do
|
211
|
-
@inst.new?.should==true
|
212
|
-
end
|
213
|
-
it "Has default values correctly set" do
|
214
|
-
@inst['age'].should==18 # direct value
|
215
|
-
@inst['subscribed_on'].class.should==Time # with proc
|
216
|
-
end
|
217
|
-
behaves_like "Has error recipient"
|
218
|
-
end
|
219
|
-
end
|
220
|
-
|
221
|
-
describe "#model" do
|
222
|
-
it "Is a shortcut for self.class" do
|
223
|
-
Naked.new.model.should==Naked
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
|
-
describe '#to_label' do
|
228
|
-
it 'Uses a built-in list of slots to pick from for a label' do
|
229
|
-
Person.new({'age'=>42, 'name'=>'Bozo', 'surname'=>'Montana', 'car'=>'Jaguar'}).to_label.should=='Montana'
|
230
|
-
end
|
231
|
-
it 'Uses an other slot declared with label_column=' do
|
232
|
-
FeatureBox.new({'header'=>'Glamour'}).to_label.should=='Glamour'
|
233
|
-
end
|
234
|
-
end
|
235
|
-
|
236
|
-
describe '#auto_slug' do
|
237
|
-
it 'Should build a url friendly slug based on #to_label' do
|
238
|
-
FeatureBox.new({'header'=>"Así es la vida by Daniel Bär & Mickaël ? (100%)"}).auto_slug.should=='Asi-es-la-vida-by-Daniel-Bar-and-Mickael-100%25'
|
239
|
-
end
|
240
|
-
end
|
241
|
-
|
242
|
-
# #default_doc
|
243
|
-
# #id
|
244
|
-
# #[]
|
245
|
-
# #[]=
|
246
|
-
# #auto_slug
|
247
|
-
# #to_slug
|
248
|
-
# #to_param
|
249
|
-
# #field_id_for
|
250
|
-
# #resolve_class
|
251
|
-
# #parent
|
252
|
-
# #slot_children
|
253
|
-
# #first_slot_child
|
254
|
-
# #children
|
255
|
-
# #first_child
|
256
|
-
# #children_count
|
257
|
-
# #delete
|
258
|
-
# #new?
|
259
|
-
# #update_doc
|
260
|
-
# #errors_on
|
261
|
-
# #valid?
|
262
|
-
# Hooks
|
263
|
-
# Validation
|
264
|
-
# Fix types
|
265
|
-
# #save
|
266
|
-
|
267
|
-
describe 'CursorMutation' do
|
268
|
-
it 'Should give the correct class of object on iterations' do
|
269
|
-
Address.new('body'=>'42').save
|
270
|
-
Address.find.each do |a|
|
271
|
-
a.model.name.should=='Address'
|
272
|
-
end
|
273
|
-
end
|
274
|
-
end
|
275
|
-
|
276
|
-
end
|
277
|
-
|
278
|
-
DB.drop
|
279
|
-
|