samlown-couchrest 0.35
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 +176 -0
- data/README.md +46 -0
- data/Rakefile +67 -0
- data/THANKS.md +19 -0
- data/examples/model/example.rb +144 -0
- data/examples/word_count/markov +38 -0
- data/examples/word_count/views/books/chunked-map.js +3 -0
- data/examples/word_count/views/books/united-map.js +1 -0
- data/examples/word_count/views/markov/chain-map.js +6 -0
- data/examples/word_count/views/markov/chain-reduce.js +7 -0
- data/examples/word_count/views/word_count/count-map.js +6 -0
- data/examples/word_count/views/word_count/count-reduce.js +3 -0
- data/examples/word_count/word_count.rb +46 -0
- data/examples/word_count/word_count_query.rb +40 -0
- data/examples/word_count/word_count_views.rb +26 -0
- data/history.txt +114 -0
- data/lib/couchrest/commands/generate.rb +71 -0
- data/lib/couchrest/commands/push.rb +103 -0
- data/lib/couchrest/core/adapters/restclient.rb +35 -0
- data/lib/couchrest/core/database.rb +377 -0
- data/lib/couchrest/core/design.rb +79 -0
- data/lib/couchrest/core/document.rb +84 -0
- data/lib/couchrest/core/http_abstraction.rb +48 -0
- data/lib/couchrest/core/response.rb +16 -0
- data/lib/couchrest/core/rest_api.rb +49 -0
- data/lib/couchrest/core/server.rb +88 -0
- data/lib/couchrest/core/view.rb +4 -0
- data/lib/couchrest/helper/pager.rb +103 -0
- data/lib/couchrest/helper/streamer.rb +51 -0
- data/lib/couchrest/helper/upgrade.rb +51 -0
- data/lib/couchrest/middlewares/logger.rb +263 -0
- data/lib/couchrest/mixins/attachments.rb +31 -0
- data/lib/couchrest/mixins/attribute_protection.rb +74 -0
- data/lib/couchrest/mixins/callbacks.rb +532 -0
- data/lib/couchrest/mixins/class_proxy.rb +124 -0
- data/lib/couchrest/mixins/collection.rb +260 -0
- data/lib/couchrest/mixins/design_doc.rb +103 -0
- data/lib/couchrest/mixins/document_queries.rb +80 -0
- data/lib/couchrest/mixins/extended_attachments.rb +70 -0
- data/lib/couchrest/mixins/extended_document_mixins.rb +9 -0
- data/lib/couchrest/mixins/properties.rb +154 -0
- data/lib/couchrest/mixins/validation.rb +246 -0
- data/lib/couchrest/mixins/views.rb +173 -0
- data/lib/couchrest/mixins.rb +4 -0
- data/lib/couchrest/monkeypatches.rb +113 -0
- data/lib/couchrest/more/casted_model.rb +58 -0
- data/lib/couchrest/more/extended_document.rb +310 -0
- data/lib/couchrest/more/property.rb +50 -0
- data/lib/couchrest/more/typecast.rb +175 -0
- data/lib/couchrest/support/blank.rb +42 -0
- data/lib/couchrest/support/class.rb +190 -0
- data/lib/couchrest/support/rails.rb +42 -0
- data/lib/couchrest/validation/auto_validate.rb +157 -0
- data/lib/couchrest/validation/contextual_validators.rb +78 -0
- data/lib/couchrest/validation/validation_errors.rb +125 -0
- data/lib/couchrest/validation/validators/absent_field_validator.rb +74 -0
- data/lib/couchrest/validation/validators/confirmation_validator.rb +107 -0
- data/lib/couchrest/validation/validators/format_validator.rb +122 -0
- data/lib/couchrest/validation/validators/formats/email.rb +66 -0
- data/lib/couchrest/validation/validators/formats/url.rb +43 -0
- data/lib/couchrest/validation/validators/generic_validator.rb +120 -0
- data/lib/couchrest/validation/validators/length_validator.rb +139 -0
- data/lib/couchrest/validation/validators/method_validator.rb +89 -0
- data/lib/couchrest/validation/validators/numeric_validator.rb +109 -0
- data/lib/couchrest/validation/validators/required_field_validator.rb +114 -0
- data/lib/couchrest.rb +162 -0
- data/spec/couchrest/core/couchrest_spec.rb +184 -0
- data/spec/couchrest/core/database_spec.rb +840 -0
- data/spec/couchrest/core/design_spec.rb +138 -0
- data/spec/couchrest/core/document_spec.rb +275 -0
- data/spec/couchrest/core/server_spec.rb +35 -0
- data/spec/couchrest/helpers/pager_spec.rb +122 -0
- data/spec/couchrest/helpers/streamer_spec.rb +52 -0
- data/spec/couchrest/more/attribute_protection_spec.rb +150 -0
- data/spec/couchrest/more/casted_extended_doc_spec.rb +79 -0
- data/spec/couchrest/more/casted_model_spec.rb +406 -0
- data/spec/couchrest/more/extended_doc_attachment_spec.rb +135 -0
- data/spec/couchrest/more/extended_doc_inherited_spec.rb +40 -0
- data/spec/couchrest/more/extended_doc_spec.rb +797 -0
- data/spec/couchrest/more/extended_doc_subclass_spec.rb +98 -0
- data/spec/couchrest/more/extended_doc_view_spec.rb +456 -0
- data/spec/couchrest/more/property_spec.rb +628 -0
- data/spec/fixtures/attachments/README +3 -0
- data/spec/fixtures/attachments/couchdb.png +0 -0
- data/spec/fixtures/attachments/test.html +11 -0
- data/spec/fixtures/more/article.rb +35 -0
- data/spec/fixtures/more/card.rb +22 -0
- data/spec/fixtures/more/cat.rb +20 -0
- data/spec/fixtures/more/course.rb +22 -0
- data/spec/fixtures/more/event.rb +8 -0
- data/spec/fixtures/more/invoice.rb +17 -0
- data/spec/fixtures/more/person.rb +9 -0
- data/spec/fixtures/more/question.rb +6 -0
- data/spec/fixtures/more/service.rb +12 -0
- data/spec/fixtures/more/user.rb +22 -0
- data/spec/fixtures/views/lib.js +3 -0
- data/spec/fixtures/views/test_view/lib.js +3 -0
- data/spec/fixtures/views/test_view/only-map.js +4 -0
- data/spec/fixtures/views/test_view/test-map.js +3 -0
- data/spec/fixtures/views/test_view/test-reduce.js +3 -0
- data/spec/spec.opts +6 -0
- data/spec/spec_helper.rb +49 -0
- data/utils/remap.rb +27 -0
- data/utils/subset.rb +30 -0
- metadata +223 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
####################################
|
|
2
|
+
# USAGE
|
|
3
|
+
#
|
|
4
|
+
# in your rack.rb file
|
|
5
|
+
# require this file and then:
|
|
6
|
+
#
|
|
7
|
+
# couch = CouchRest.new
|
|
8
|
+
# LOG_DB = couch.database!('couchrest-logger')
|
|
9
|
+
# use CouchRest::Logger, LOG_DB
|
|
10
|
+
#
|
|
11
|
+
# Note:
|
|
12
|
+
# to require just this middleware, if you have the gem installed do:
|
|
13
|
+
# require 'couchrest/middlewares/logger'
|
|
14
|
+
#
|
|
15
|
+
# For log processing examples, see examples at the bottom of this file
|
|
16
|
+
|
|
17
|
+
module CouchRest
|
|
18
|
+
class Logger
|
|
19
|
+
|
|
20
|
+
def self.log
|
|
21
|
+
Thread.current["couchrest.logger"] ||= {:queries => []}
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def initialize(app, db=nil)
|
|
25
|
+
@app = app
|
|
26
|
+
@db = db
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def self.record(log_info)
|
|
30
|
+
log[:queries] << log_info
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def log
|
|
34
|
+
Thread.current["couchrest.logger"] ||= {:queries => []}
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def reset_log
|
|
38
|
+
Thread.current["couchrest.logger"] = nil
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def call(env)
|
|
42
|
+
reset_log
|
|
43
|
+
log['started_at'] = Time.now
|
|
44
|
+
log['env'] = env
|
|
45
|
+
log['url'] = 'http://' + env['HTTP_HOST'] + env['REQUEST_URI']
|
|
46
|
+
response = @app.call(env)
|
|
47
|
+
log['ended_at'] = Time.now
|
|
48
|
+
log['duration'] = log['ended_at'] - log['started_at']
|
|
49
|
+
# let's report the log in a different thread so we don't slow down the app
|
|
50
|
+
@db ? Thread.new(@db, log){|db, rlog| db.save_doc(rlog);} : p(log.inspect)
|
|
51
|
+
response
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# inject our logger into CouchRest HTTP abstraction layer
|
|
57
|
+
module HttpAbstraction
|
|
58
|
+
|
|
59
|
+
def self.get(uri, headers=nil)
|
|
60
|
+
start_query = Time.now
|
|
61
|
+
log = {:method => :get, :uri => uri, :headers => headers}
|
|
62
|
+
response = super(uri, headers=nil)
|
|
63
|
+
end_query = Time.now
|
|
64
|
+
log[:duration] = (end_query - start_query)
|
|
65
|
+
CouchRest::Logger.record(log)
|
|
66
|
+
response
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def self.post(uri, payload, headers=nil)
|
|
70
|
+
start_query = Time.now
|
|
71
|
+
log = {:method => :post, :uri => uri, :payload => (payload ? (JSON.load(payload) rescue 'parsing error') : nil), :headers => headers}
|
|
72
|
+
response = super(uri, payload, headers=nil)
|
|
73
|
+
end_query = Time.now
|
|
74
|
+
log[:duration] = (end_query - start_query)
|
|
75
|
+
CouchRest::Logger.record(log)
|
|
76
|
+
response
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def self.put(uri, payload, headers=nil)
|
|
80
|
+
start_query = Time.now
|
|
81
|
+
log = {:method => :put, :uri => uri, :payload => (payload ? (JSON.load(payload) rescue 'parsing error') : nil), :headers => headers}
|
|
82
|
+
response = super(uri, payload, headers=nil)
|
|
83
|
+
end_query = Time.now
|
|
84
|
+
log[:duration] = (end_query - start_query)
|
|
85
|
+
CouchRest::Logger.record(log)
|
|
86
|
+
response
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def self.delete(uri, headers=nil)
|
|
90
|
+
start_query = Time.now
|
|
91
|
+
log = {:method => :delete, :uri => uri, :headers => headers}
|
|
92
|
+
response = super(uri, headers=nil)
|
|
93
|
+
end_query = Time.now
|
|
94
|
+
log[:duration] = (end_query - start_query)
|
|
95
|
+
CouchRest::Logger.record(log)
|
|
96
|
+
response
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
# Advanced usage example
|
|
103
|
+
#
|
|
104
|
+
#
|
|
105
|
+
# # DB VIEWS
|
|
106
|
+
# by_url = {
|
|
107
|
+
# :map =>
|
|
108
|
+
# "function(doc) {
|
|
109
|
+
# if(doc['url']){ emit(doc['url'], 1) };
|
|
110
|
+
# }",
|
|
111
|
+
# :reduce =>
|
|
112
|
+
# 'function (key, values, rereduce) {
|
|
113
|
+
# return(sum(values));
|
|
114
|
+
# };'
|
|
115
|
+
# }
|
|
116
|
+
# req_duration = {
|
|
117
|
+
# :map =>
|
|
118
|
+
# "function(doc) {
|
|
119
|
+
# if(doc['duration']){ emit(doc['url'], doc['duration']) };
|
|
120
|
+
# }",
|
|
121
|
+
# :reduce =>
|
|
122
|
+
# 'function (key, values, rereduce) {
|
|
123
|
+
# return(sum(values)/values.length);
|
|
124
|
+
# };'
|
|
125
|
+
# }
|
|
126
|
+
#
|
|
127
|
+
# query_duration = {
|
|
128
|
+
# :map =>
|
|
129
|
+
# "function(doc) {
|
|
130
|
+
# if(doc['queries']){
|
|
131
|
+
# doc.queries.forEach(function(query){
|
|
132
|
+
# if(query['duration'] && query['method']){
|
|
133
|
+
# emit(query['method'], query['duration'])
|
|
134
|
+
# }
|
|
135
|
+
# });
|
|
136
|
+
# };
|
|
137
|
+
# }" ,
|
|
138
|
+
# :reduce =>
|
|
139
|
+
# 'function (key, values, rereduce) {
|
|
140
|
+
# return(sum(values)/values.length);
|
|
141
|
+
# };'
|
|
142
|
+
# }
|
|
143
|
+
#
|
|
144
|
+
# action_queries = {
|
|
145
|
+
# :map =>
|
|
146
|
+
# "function(doc) {
|
|
147
|
+
# if(doc['queries']){
|
|
148
|
+
# emit(doc['url'], doc['queries'].length)
|
|
149
|
+
# };
|
|
150
|
+
# }",
|
|
151
|
+
# :reduce =>
|
|
152
|
+
# 'function (key, values, rereduce) {
|
|
153
|
+
# return(sum(values)/values.length);
|
|
154
|
+
# };'
|
|
155
|
+
# }
|
|
156
|
+
#
|
|
157
|
+
# action_time_spent_in_db = {
|
|
158
|
+
# :map =>
|
|
159
|
+
# "function(doc) {
|
|
160
|
+
# if(doc['queries']){
|
|
161
|
+
# var totalDuration = 0;
|
|
162
|
+
# doc.queries.forEach(function(query){
|
|
163
|
+
# totalDuration += query['duration']
|
|
164
|
+
# })
|
|
165
|
+
# emit(doc['url'], totalDuration)
|
|
166
|
+
# };
|
|
167
|
+
# }",
|
|
168
|
+
# :reduce =>
|
|
169
|
+
# 'function (key, values, rereduce) {
|
|
170
|
+
# return(sum(values)/values.length);
|
|
171
|
+
# };'
|
|
172
|
+
# }
|
|
173
|
+
#
|
|
174
|
+
# show_queries = %Q~function(doc, req) {
|
|
175
|
+
# var body = ""
|
|
176
|
+
# body += "<h1>" + doc['url'] + "</h1>"
|
|
177
|
+
# body += "<h2>Request duration in seconds: " + doc['duration'] + "</h2>"
|
|
178
|
+
# body += "<h3>" + doc['queries'].length + " queries</h3><ul>"
|
|
179
|
+
# if (doc.queries){
|
|
180
|
+
# doc.queries.forEach(function(query){
|
|
181
|
+
# body += "<li>"+ query['uri'] +"</li>"
|
|
182
|
+
# });
|
|
183
|
+
# };
|
|
184
|
+
# body += "</ul>"
|
|
185
|
+
# if(doc){ return { body: body} }
|
|
186
|
+
# }~
|
|
187
|
+
#
|
|
188
|
+
#
|
|
189
|
+
# couch = CouchRest.new
|
|
190
|
+
# LOG_DB = couch.database!('couchrest-logger')
|
|
191
|
+
# design_doc = LOG_DB.get("_design/stats") rescue nil
|
|
192
|
+
# LOG_DB.delete_doc design_doc rescue nil
|
|
193
|
+
# LOG_DB.save_doc({
|
|
194
|
+
# "_id" => "_design/stats",
|
|
195
|
+
# :views => {
|
|
196
|
+
# :by_url => by_url,
|
|
197
|
+
# :request_duration => req_duration,
|
|
198
|
+
# :query_duration => query_duration,
|
|
199
|
+
# :action_queries => action_queries,
|
|
200
|
+
# :action_time_spent_in_db => action_time_spent_in_db
|
|
201
|
+
# },
|
|
202
|
+
# :shows => {
|
|
203
|
+
# :queries => show_queries
|
|
204
|
+
# }
|
|
205
|
+
# })
|
|
206
|
+
#
|
|
207
|
+
# module CouchRest
|
|
208
|
+
# class Logger
|
|
209
|
+
#
|
|
210
|
+
# def self.roundup(value)
|
|
211
|
+
# begin
|
|
212
|
+
# value = Float(value)
|
|
213
|
+
# (value * 100).round.to_f / 100
|
|
214
|
+
# rescue
|
|
215
|
+
# value
|
|
216
|
+
# end
|
|
217
|
+
# end
|
|
218
|
+
#
|
|
219
|
+
# # Usage example:
|
|
220
|
+
# # CouchRest::Logger.average_request_duration(LOG_DB)['rows'].first['value']
|
|
221
|
+
# def self.average_request_duration(db)
|
|
222
|
+
# raw = db.view('stats/request_duration', :reduce => true)
|
|
223
|
+
# (raw.has_key?('rows') && !raw['rows'].empty?) ? roundup(raw['rows'].first['value']) : 'not available yet'
|
|
224
|
+
# end
|
|
225
|
+
#
|
|
226
|
+
# def self.average_query_duration(db)
|
|
227
|
+
# raw = db.view('stats/query_duration', :reduce => true)
|
|
228
|
+
# (raw.has_key?('rows') && !raw['rows'].empty?) ? roundup(raw['rows'].first['value']) : 'not available yet'
|
|
229
|
+
# end
|
|
230
|
+
#
|
|
231
|
+
# def self.average_get_query_duration(db)
|
|
232
|
+
# raw = db.view('stats/query_duration', :key => 'get', :reduce => true)
|
|
233
|
+
# (raw.has_key?('rows') && !raw['rows'].empty?) ? roundup(raw['rows'].first['value']) : 'not available yet'
|
|
234
|
+
# end
|
|
235
|
+
#
|
|
236
|
+
# def self.average_post_query_duration(db)
|
|
237
|
+
# raw = db.view('stats/query_duration', :key => 'post', :reduce => true)
|
|
238
|
+
# (raw.has_key?('rows') && !raw['rows'].empty?) ? roundup(raw['rows'].first['value']) : 'not available yet'
|
|
239
|
+
# end
|
|
240
|
+
#
|
|
241
|
+
# def self.average_queries_per_action(db)
|
|
242
|
+
# raw = db.view('stats/action_queries', :reduce => true)
|
|
243
|
+
# (raw.has_key?('rows') && !raw['rows'].empty?) ? roundup(raw['rows'].first['value']) : 'not available yet'
|
|
244
|
+
# end
|
|
245
|
+
#
|
|
246
|
+
# def self.average_db_time_per_action(db)
|
|
247
|
+
# raw = db.view('stats/action_time_spent_in_db', :reduce => true)
|
|
248
|
+
# (raw.has_key?('rows') && !raw['rows'].empty?) ? roundup(raw['rows'].first['value']) : 'not available yet'
|
|
249
|
+
# end
|
|
250
|
+
#
|
|
251
|
+
# def self.stats(db)
|
|
252
|
+
# Thread.new(db){|db|
|
|
253
|
+
# puts "=== STATS ===\n"
|
|
254
|
+
# puts "average request duration: #{average_request_duration(db)}\n"
|
|
255
|
+
# puts "average query duration: #{average_query_duration(db)}\n"
|
|
256
|
+
# puts "average queries per action : #{average_queries_per_action(db)}\n"
|
|
257
|
+
# puts "average time spent in DB (per action): #{average_db_time_per_action(db)}\n"
|
|
258
|
+
# puts "===============\n"
|
|
259
|
+
# }
|
|
260
|
+
# end
|
|
261
|
+
#
|
|
262
|
+
# end
|
|
263
|
+
# end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module CouchRest
|
|
2
|
+
module Mixins
|
|
3
|
+
module Attachments
|
|
4
|
+
|
|
5
|
+
# saves an attachment directly to couchdb
|
|
6
|
+
def put_attachment(name, file, options={})
|
|
7
|
+
raise ArgumentError, "doc must be saved" unless self.rev
|
|
8
|
+
raise ArgumentError, "doc.database required to put_attachment" unless database
|
|
9
|
+
result = database.put_attachment(self, name, file, options)
|
|
10
|
+
self['_rev'] = result['rev']
|
|
11
|
+
result['ok']
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# returns an attachment's data
|
|
15
|
+
def fetch_attachment(name)
|
|
16
|
+
raise ArgumentError, "doc must be saved" unless self.rev
|
|
17
|
+
raise ArgumentError, "doc.database required to put_attachment" unless database
|
|
18
|
+
database.fetch_attachment(self, name)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# deletes an attachment directly from couchdb
|
|
22
|
+
def delete_attachment(name, force=false)
|
|
23
|
+
raise ArgumentError, "doc.database required to delete_attachment" unless database
|
|
24
|
+
result = database.delete_attachment(self, name, force)
|
|
25
|
+
self['_rev'] = result['rev']
|
|
26
|
+
result['ok']
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
module CouchRest
|
|
2
|
+
module Mixins
|
|
3
|
+
module AttributeProtection
|
|
4
|
+
# Attribute protection from mass assignment to CouchRest properties
|
|
5
|
+
#
|
|
6
|
+
# Protected methods will be removed from
|
|
7
|
+
# * new
|
|
8
|
+
# * update_attributes
|
|
9
|
+
# * upate_attributes_without_saving
|
|
10
|
+
# * attributes=
|
|
11
|
+
#
|
|
12
|
+
# There are two modes of protection
|
|
13
|
+
# 1) Declare accessible poperties, assume all the rest are protected
|
|
14
|
+
# property :name, :accessible => true
|
|
15
|
+
# property :admin # this will be automatically protected
|
|
16
|
+
#
|
|
17
|
+
# 2) Declare protected properties, assume all the rest are accessible
|
|
18
|
+
# property :name # this will not be protected
|
|
19
|
+
# property :admin, :protected => true
|
|
20
|
+
#
|
|
21
|
+
# Note: you cannot set both flags in a single class
|
|
22
|
+
|
|
23
|
+
def self.included(base)
|
|
24
|
+
base.extend(ClassMethods)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
module ClassMethods
|
|
28
|
+
def accessible_properties
|
|
29
|
+
properties.select { |prop| prop.options[:accessible] }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def protected_properties
|
|
33
|
+
properties.select { |prop| prop.options[:protected] }
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def accessible_properties
|
|
38
|
+
self.class.accessible_properties
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def protected_properties
|
|
42
|
+
self.class.protected_properties
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def remove_protected_attributes(attributes)
|
|
46
|
+
protected_names = properties_to_remove_from_mass_assignment.map { |prop| prop.name }
|
|
47
|
+
return attributes if protected_names.empty?
|
|
48
|
+
|
|
49
|
+
attributes.reject! do |property_name, property_value|
|
|
50
|
+
protected_names.include?(property_name.to_s)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
attributes || {}
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
def properties_to_remove_from_mass_assignment
|
|
59
|
+
has_protected = !protected_properties.empty?
|
|
60
|
+
has_accessible = !accessible_properties.empty?
|
|
61
|
+
|
|
62
|
+
if !has_protected && !has_accessible
|
|
63
|
+
[]
|
|
64
|
+
elsif has_protected && !has_accessible
|
|
65
|
+
protected_properties
|
|
66
|
+
elsif has_accessible && !has_protected
|
|
67
|
+
properties.reject { |prop| prop.options[:accessible] }
|
|
68
|
+
else
|
|
69
|
+
raise "Set either :accessible or :protected for #{self.class}, but not both"
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|