api_resource 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- metadata +179 -123
- data/.document +0 -5
- data/.rspec +0 -5
- data/.travis.yml +0 -4
- data/Gemfile +0 -37
- data/Gemfile.lock +0 -190
- data/Guardfile +0 -27
- data/Rakefile +0 -49
- data/VERSION +0 -1
- data/api_resource.gemspec +0 -180
- data/lib/api_resource.rb +0 -130
- data/lib/api_resource/association_activation.rb +0 -19
- data/lib/api_resource/associations.rb +0 -218
- data/lib/api_resource/associations/association_proxy.rb +0 -116
- data/lib/api_resource/associations/belongs_to_remote_object_proxy.rb +0 -16
- data/lib/api_resource/associations/dynamic_resource_scope.rb +0 -23
- data/lib/api_resource/associations/generic_scope.rb +0 -68
- data/lib/api_resource/associations/has_many_remote_object_proxy.rb +0 -16
- data/lib/api_resource/associations/has_many_through_remote_object_proxy.rb +0 -13
- data/lib/api_resource/associations/has_one_remote_object_proxy.rb +0 -24
- data/lib/api_resource/associations/multi_argument_resource_scope.rb +0 -15
- data/lib/api_resource/associations/multi_object_proxy.rb +0 -84
- data/lib/api_resource/associations/related_object_hash.rb +0 -12
- data/lib/api_resource/associations/relation_scope.rb +0 -25
- data/lib/api_resource/associations/resource_scope.rb +0 -32
- data/lib/api_resource/associations/scope.rb +0 -132
- data/lib/api_resource/associations/single_object_proxy.rb +0 -82
- data/lib/api_resource/attributes.rb +0 -243
- data/lib/api_resource/base.rb +0 -717
- data/lib/api_resource/callbacks.rb +0 -45
- data/lib/api_resource/connection.rb +0 -195
- data/lib/api_resource/core_extensions.rb +0 -7
- data/lib/api_resource/custom_methods.rb +0 -117
- data/lib/api_resource/decorators.rb +0 -6
- data/lib/api_resource/decorators/caching_decorator.rb +0 -20
- data/lib/api_resource/exceptions.rb +0 -99
- data/lib/api_resource/formats.rb +0 -22
- data/lib/api_resource/formats/json_format.rb +0 -25
- data/lib/api_resource/formats/xml_format.rb +0 -36
- data/lib/api_resource/local.rb +0 -12
- data/lib/api_resource/log_subscriber.rb +0 -15
- data/lib/api_resource/mocks.rb +0 -277
- data/lib/api_resource/model_errors.rb +0 -82
- data/lib/api_resource/observing.rb +0 -27
- data/lib/api_resource/railtie.rb +0 -24
- data/lib/api_resource/scopes.rb +0 -48
- data/nohup.out +0 -63
- data/spec/lib/api_resource_spec.rb +0 -43
- data/spec/lib/associations_spec.rb +0 -751
- data/spec/lib/attributes_spec.rb +0 -191
- data/spec/lib/base_spec.rb +0 -655
- data/spec/lib/callbacks_spec.rb +0 -68
- data/spec/lib/connection_spec.rb +0 -137
- data/spec/lib/local_spec.rb +0 -20
- data/spec/lib/mocks_spec.rb +0 -45
- data/spec/lib/model_errors_spec.rb +0 -29
- data/spec/lib/prefixes_spec.rb +0 -107
- data/spec/spec_helper.rb +0 -82
- data/spec/support/mocks/association_mocks.rb +0 -63
- data/spec/support/mocks/error_resource_mocks.rb +0 -21
- data/spec/support/mocks/prefix_model_mocks.rb +0 -5
- data/spec/support/mocks/test_resource_mocks.rb +0 -44
- data/spec/support/requests/association_requests.rb +0 -31
- data/spec/support/requests/error_resource_requests.rb +0 -25
- data/spec/support/requests/prefix_model_requests.rb +0 -7
- data/spec/support/requests/test_resource_requests.rb +0 -38
- data/spec/support/test_resource.rb +0 -72
- data/spec/tmp/DIR +0 -0
@@ -1,16 +0,0 @@
|
|
1
|
-
require 'api_resource/associations/single_object_proxy'
|
2
|
-
module ApiResource
|
3
|
-
module Associations
|
4
|
-
class BelongsToRemoteObjectProxy < SingleObjectProxy
|
5
|
-
def initialize(klass_name, contents, owner)
|
6
|
-
super
|
7
|
-
return if self.internal_object
|
8
|
-
# now if we have an owner and a foreign key, we set the data up to load
|
9
|
-
if owner && key = owner.send(self.klass.to_s.foreign_key)
|
10
|
-
self.load({"service_uri" => self.klass.element_path(key), "scopes_only" => true}.merge(self.klass.scopes))
|
11
|
-
end
|
12
|
-
true
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
require 'api_resource/associations/resource_scope'
|
2
|
-
|
3
|
-
module ApiResource
|
4
|
-
module Associations
|
5
|
-
class DynamicResourceScope < ResourceScope
|
6
|
-
|
7
|
-
attr_accessor :dynamic_value
|
8
|
-
# initializer - set up the dynamic value
|
9
|
-
def initialize(klass, current_scope, dynamic_value, opts = {})
|
10
|
-
self.dynamic_value = dynamic_value
|
11
|
-
super(klass, current_scope, opts)
|
12
|
-
end
|
13
|
-
# get the to_query value for this resource scope
|
14
|
-
def to_hash
|
15
|
-
hsh = self.scopes[self.current_scope].clone
|
16
|
-
hsh.each_pair do |k,v|
|
17
|
-
hsh[k] = self.dynamic_value
|
18
|
-
end
|
19
|
-
self.parent_hash.merge(hsh)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
@@ -1,68 +0,0 @@
|
|
1
|
-
require 'api_resource/associations/resource_scope'
|
2
|
-
|
3
|
-
module ApiResource
|
4
|
-
module Associations
|
5
|
-
|
6
|
-
class GenericScope < ResourceScope
|
7
|
-
attr_reader :name
|
8
|
-
attr_reader :params
|
9
|
-
attr_reader :types
|
10
|
-
attr_reader :values
|
11
|
-
|
12
|
-
# Gets called when a scope is called. Stores everything in
|
13
|
-
# this class. Sorry, couldn't be bothered to figure out the
|
14
|
-
# class hierarchy.
|
15
|
-
#
|
16
|
-
# klass - ApiResourceBase class
|
17
|
-
# current_scope - sym for the scope
|
18
|
-
# *args - arguments being passed to the scope
|
19
|
-
def initialize(klass, current_scope, *args)
|
20
|
-
|
21
|
-
@name = current_scope # contains sym with scope ie :for_provider
|
22
|
-
@params = klass.related_objects[:scopes][current_scope].keys
|
23
|
-
@types = klass.related_objects[:scopes][current_scope].values
|
24
|
-
|
25
|
-
# Bail if we have crap
|
26
|
-
if @params == nil
|
27
|
-
raise "Scope #{@name} does not exist #{klass.name}. Scopes: #{klass.related_objects[:scopes]}"
|
28
|
-
end
|
29
|
-
|
30
|
-
# extract parent scope stuff
|
31
|
-
opts = {}
|
32
|
-
last_arg = args[args.count - 1]
|
33
|
-
if last_arg != nil && last_arg.is_a?(Hash) && last_arg[:parent] != nil
|
34
|
-
args = args.slice(0, args.count - 1)
|
35
|
-
opts = last_arg
|
36
|
-
end
|
37
|
-
|
38
|
-
# walk through parameters and types and assign values from *args to parameters
|
39
|
-
@values = []
|
40
|
-
@params.count.times do |i|
|
41
|
-
if @types[i] == :rest
|
42
|
-
@values << args.slice(i, args.count)
|
43
|
-
else
|
44
|
-
@values << args[i]
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
# Let the parent class do its magic.
|
49
|
-
super(klass, current_scope, opts)
|
50
|
-
end
|
51
|
-
|
52
|
-
# get the to_query value for this resource scope
|
53
|
-
def to_hash
|
54
|
-
# debugger
|
55
|
-
if @params.count == 0
|
56
|
-
scope_arguments = true
|
57
|
-
else
|
58
|
-
scope_arguments = {}
|
59
|
-
@params.count.times do |i|
|
60
|
-
scope_arguments[@params[i]] = @values[i] if @values[i] != nil
|
61
|
-
end
|
62
|
-
end
|
63
|
-
self.parent_hash.merge({@name => scope_arguments})
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
@@ -1,16 +0,0 @@
|
|
1
|
-
require 'api_resource/associations/multi_object_proxy'
|
2
|
-
module ApiResource
|
3
|
-
module Associations
|
4
|
-
class HasManyRemoteObjectProxy < MultiObjectProxy
|
5
|
-
def initialize(klass_name, contents, owner)
|
6
|
-
super
|
7
|
-
return if self.internal_object.present? || self.remote_path
|
8
|
-
# now if we have an owner and a foreign key, we set the data up to load
|
9
|
-
if owner
|
10
|
-
self.load({"service_uri" => self.klass.collection_path(self.owner.class.to_s.foreign_key => self.owner.id)}.merge(self.klass.scopes))
|
11
|
-
end
|
12
|
-
true
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
@@ -1,13 +0,0 @@
|
|
1
|
-
module ApiResource
|
2
|
-
module Associations
|
3
|
-
module HasManyThroughRemoteObjectProxy
|
4
|
-
def has_many_through_remote(association, options)
|
5
|
-
self.instance_eval do
|
6
|
-
send(:define_method, association) do
|
7
|
-
send(options[:through]).collect{ |t| t.send(association.to_s.singularize) }.flatten
|
8
|
-
end
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
require 'api_resource/associations/single_object_proxy'
|
2
|
-
module ApiResource
|
3
|
-
module Associations
|
4
|
-
class HasOneRemoteObjectProxy < SingleObjectProxy
|
5
|
-
def initialize(klass_name, contents, owner)
|
6
|
-
super
|
7
|
-
return if self.internal_object
|
8
|
-
# now if we have an owner and a foreign key, we set the data up to load
|
9
|
-
if owner
|
10
|
-
self.load({"service_uri" => self.klass.collection_path(self.owner.class.to_s.foreign_key => self.owner.id)}.merge(self.klass.scopes))
|
11
|
-
end
|
12
|
-
true
|
13
|
-
end
|
14
|
-
protected
|
15
|
-
# load data from the remote server
|
16
|
-
# In a has_one, we can get back an Array, so we use the first element
|
17
|
-
def load_from_remote(options)
|
18
|
-
data = super(options)
|
19
|
-
data = data.first if data.is_a?(Array)
|
20
|
-
data
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
require 'api_resource/associations/dynamic_resource_scope'
|
2
|
-
|
3
|
-
module ApiResource
|
4
|
-
module Associations
|
5
|
-
class MultiArgumentResourceScope < DynamicResourceScope
|
6
|
-
# initialize with a variable number of dynamic arguments
|
7
|
-
def initialize(klass, current_scope, *dynamic_value)
|
8
|
-
# pull off opts
|
9
|
-
opts = dynamic_value.extract_options!
|
10
|
-
# we always dynamic value to be an Array, so we don't use the splat here
|
11
|
-
super(klass, current_scope, dynamic_value.flatten, opts)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
@@ -1,84 +0,0 @@
|
|
1
|
-
require 'api_resource/associations/association_proxy'
|
2
|
-
|
3
|
-
module ApiResource
|
4
|
-
|
5
|
-
module Associations
|
6
|
-
|
7
|
-
class MultiObjectProxy < AssociationProxy
|
8
|
-
|
9
|
-
include Enumerable
|
10
|
-
|
11
|
-
def all
|
12
|
-
self.internal_object
|
13
|
-
end
|
14
|
-
|
15
|
-
def each(*args, &block)
|
16
|
-
self.internal_object.each(*args, &block)
|
17
|
-
end
|
18
|
-
|
19
|
-
def ==(other)
|
20
|
-
return false if self.class != other.class
|
21
|
-
if self.internal_object.is_a?(Array)
|
22
|
-
self.internal_object.sort.each_with_index do |elem, i|
|
23
|
-
return false if other.internal_object.sort[i].attributes != elem.attributes
|
24
|
-
end
|
25
|
-
end
|
26
|
-
return true
|
27
|
-
end
|
28
|
-
|
29
|
-
def serializable_hash(options)
|
30
|
-
self.internal_object.collect{|obj| obj.serializable_hash(options) }
|
31
|
-
end
|
32
|
-
|
33
|
-
# force a load when calling this method
|
34
|
-
def internal_object
|
35
|
-
@internal_object ||= self.load_scope_with_options(:all, {})
|
36
|
-
end
|
37
|
-
|
38
|
-
def internal_object=(contents)
|
39
|
-
return @internal_object = contents if contents.all?{|o| o.is_a?(self.klass)}
|
40
|
-
return load(contents)
|
41
|
-
end
|
42
|
-
|
43
|
-
protected
|
44
|
-
def load_scope_with_options(scope, options)
|
45
|
-
scope = self.loaded_hash_key(scope.to_s, options)
|
46
|
-
return [] if self.remote_path.blank?
|
47
|
-
|
48
|
-
self.loaded[scope] ||= begin
|
49
|
-
self.times_loaded += 1
|
50
|
-
self.load_from_remote(options).collect{|item| self.klass.new(item)}
|
51
|
-
end
|
52
|
-
|
53
|
-
end
|
54
|
-
|
55
|
-
def load(contents)
|
56
|
-
@internal_object = [] and return nil if contents.blank?
|
57
|
-
if contents.is_a?(Array) && contents.first.is_a?(Hash) && contents.first[self.class.remote_path_element]
|
58
|
-
settings = contents.slice!(0).with_indifferent_access
|
59
|
-
end
|
60
|
-
|
61
|
-
settings = contents.with_indifferent_access if contents.is_a?(Hash)
|
62
|
-
settings ||= {}.with_indifferent_access
|
63
|
-
|
64
|
-
raise "Invalid response for multi object relationship: #{contents}" unless settings[self.class.remote_path_element] || contents.is_a?(Array)
|
65
|
-
self.remote_path = settings.delete(self.class.remote_path_element)
|
66
|
-
|
67
|
-
settings.each do |key, value|
|
68
|
-
raise "Expected the scope #{key} to point to a hash, to #{value}" unless value.is_a?(Hash)
|
69
|
-
self.instance_eval <<-EOE, __FILE__, __LINE__ + 1
|
70
|
-
def #{key}(opts = {})
|
71
|
-
@#{key} ||= ApiResource::Associations::RelationScope.new(self, :#{key}, opts)
|
72
|
-
end
|
73
|
-
EOE
|
74
|
-
self.scopes[key.to_s] = value
|
75
|
-
end
|
76
|
-
|
77
|
-
# Create the internal object
|
78
|
-
@internal_object = contents.is_a?(Array) ? contents.collect{|item| self.klass.new(item)} : nil
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
end
|
83
|
-
|
84
|
-
end
|
@@ -1,12 +0,0 @@
|
|
1
|
-
module ApiResource
|
2
|
-
module Associations
|
3
|
-
# RelatedObjectHash, re-defines dup to be recursive
|
4
|
-
class RelatedObjectHash < HashWithIndifferentAccess
|
5
|
-
def dup
|
6
|
-
Marshal.load(Marshal.dump(self))
|
7
|
-
end
|
8
|
-
# use this behavior for clone too
|
9
|
-
alias_method :clone, :dup
|
10
|
-
end
|
11
|
-
end
|
12
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
require 'api_resource/associations/scope'
|
2
|
-
|
3
|
-
module ApiResource
|
4
|
-
|
5
|
-
module Associations
|
6
|
-
|
7
|
-
class RelationScope < Scope
|
8
|
-
|
9
|
-
# Use this method to access the internal data, this guarantees that loading only occurs once per object
|
10
|
-
def internal_object
|
11
|
-
ApiResource.with_ttl(ttl) do
|
12
|
-
@internal_object ||= self.klass.send(:load_scope_with_options, self.current_scope, self.to_hash)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
#
|
16
|
-
# class factory
|
17
|
-
def self.class_factory(hsh)
|
18
|
-
ApiResource::Associations::RelationScope
|
19
|
-
end
|
20
|
-
|
21
|
-
end
|
22
|
-
|
23
|
-
end
|
24
|
-
|
25
|
-
end
|
@@ -1,32 +0,0 @@
|
|
1
|
-
require 'api_resource/associations/scope'
|
2
|
-
|
3
|
-
module ApiResource
|
4
|
-
|
5
|
-
module Associations
|
6
|
-
|
7
|
-
class ResourceScope < Scope
|
8
|
-
|
9
|
-
include Enumerable
|
10
|
-
|
11
|
-
def internal_object
|
12
|
-
ApiResource.with_ttl(ttl) do
|
13
|
-
@internal_object ||= self.klass.send(:find, :all, :params => self.to_hash)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
alias_method :all, :internal_object
|
18
|
-
|
19
|
-
def each(*args, &block)
|
20
|
-
self.internal_object.each(*args, &block)
|
21
|
-
end
|
22
|
-
|
23
|
-
# Used by ApiResource::Scopes to create methods with the same name
|
24
|
-
# as the scope
|
25
|
-
#
|
26
|
-
# Weird place to have a factory... could have been on Scope or a separate class...
|
27
|
-
def self.class_factory(hsh)
|
28
|
-
return ApiResource::Associations::GenericScope
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
@@ -1,132 +0,0 @@
|
|
1
|
-
module ApiResource
|
2
|
-
|
3
|
-
module Associations
|
4
|
-
|
5
|
-
class Scope
|
6
|
-
|
7
|
-
attr_accessor :klass, :current_scope, :internal_object
|
8
|
-
|
9
|
-
attr_reader :scopes
|
10
|
-
|
11
|
-
def initialize(klass, current_scope, opts = {})
|
12
|
-
# Holds onto the association proxy this RelationScope is bound to
|
13
|
-
@klass = klass
|
14
|
-
@parent = opts.delete(:parent)
|
15
|
-
@ttl = opts.delete(:expires_in)
|
16
|
-
# splits on _and_ and sorts to get a consistent scope key order
|
17
|
-
@current_scope = (self.parent_scope + Array.wrap(current_scope.to_s)).sort
|
18
|
-
# define methods for the scopes of the object
|
19
|
-
|
20
|
-
klass.scopes.each do |key, val|
|
21
|
-
self.instance_eval <<-EOE, __FILE__, __LINE__ + 1
|
22
|
-
# This class always has at least one scope, adding a new one should clone this object
|
23
|
-
def #{key}(*args)
|
24
|
-
obj = self.clone
|
25
|
-
# Call reload to make it go back to the webserver the next time it loads
|
26
|
-
obj.reload
|
27
|
-
return obj.enhance_current_scope(:#{key}, *args)
|
28
|
-
end
|
29
|
-
EOE
|
30
|
-
self.scopes[key.to_s] = val
|
31
|
-
end
|
32
|
-
# Use the method current scope because it gives a string
|
33
|
-
# This expression substitutes the options from opts into the default attributes of the scope, it will only copy keys that exist in the original
|
34
|
-
self.scopes[self.current_scope] = opts.inject(self.scopes[current_scope]){|accum,(k,v)| accum.key?(k.to_s) ? accum.merge(k.to_s => v) : accum}
|
35
|
-
end
|
36
|
-
|
37
|
-
def ttl
|
38
|
-
@ttl || 0
|
39
|
-
end
|
40
|
-
|
41
|
-
# Use this method to access the internal data, this guarantees that loading only occurs once per object
|
42
|
-
def internal_object
|
43
|
-
raise "Not Implemented: This method must be implemented in a subclass"
|
44
|
-
end
|
45
|
-
|
46
|
-
def scopes
|
47
|
-
@scopes ||= {}.with_indifferent_access
|
48
|
-
end
|
49
|
-
|
50
|
-
def scope?(scp)
|
51
|
-
self.scopes.key?(scp.to_s)
|
52
|
-
end
|
53
|
-
|
54
|
-
def current_scope
|
55
|
-
ActiveSupport::StringInquirer.new(@current_scope.join("_and_").concat("_scope"))
|
56
|
-
end
|
57
|
-
|
58
|
-
def to_hash
|
59
|
-
self.parent_hash.merge(self.scopes[self.current_scope])
|
60
|
-
end
|
61
|
-
|
62
|
-
# takes empty hashes and replaces them with true so that to_query doesn't strip them out
|
63
|
-
def to_query_safe_hash(hash)
|
64
|
-
hash.each_pair do |k, v|
|
65
|
-
hash[k] = to_query_safe_hash(v) if v.is_a?(Hash)
|
66
|
-
hash[k] = true if v == {}
|
67
|
-
end
|
68
|
-
return hash
|
69
|
-
end
|
70
|
-
|
71
|
-
# gets the current hash and calls to_query on it
|
72
|
-
def to_query
|
73
|
-
#We need to add the unescape because to_query breaks on nested arrays
|
74
|
-
CGI.unescape(to_query_safe_hash(self.to_hash).to_query)
|
75
|
-
end
|
76
|
-
|
77
|
-
def method_missing(method, *args, &block)
|
78
|
-
self.internal_object.send(method, *args, &block)
|
79
|
-
end
|
80
|
-
|
81
|
-
def reload
|
82
|
-
remove_instance_variable(:@internal_object) if instance_variable_defined?(:@internal_object)
|
83
|
-
self
|
84
|
-
end
|
85
|
-
|
86
|
-
def to_s
|
87
|
-
self.internal_object.to_s
|
88
|
-
end
|
89
|
-
|
90
|
-
def inspect
|
91
|
-
self.internal_object.inspect
|
92
|
-
end
|
93
|
-
|
94
|
-
def blank?
|
95
|
-
self.internal_object.blank?
|
96
|
-
end
|
97
|
-
alias_method :empty?, :blank?
|
98
|
-
|
99
|
-
def present?
|
100
|
-
self.internal_object.present?
|
101
|
-
end
|
102
|
-
|
103
|
-
def expires_in(ttl)
|
104
|
-
ApiResource::Decorators::CachingDecorator.new(self, ttl)
|
105
|
-
end
|
106
|
-
|
107
|
-
protected
|
108
|
-
# scope from the parent
|
109
|
-
def parent_scope
|
110
|
-
ret = @parent ? Array.wrap(@parent.current_scope).collect{|el| el.gsub(/_scope$/,'')} : []
|
111
|
-
ret.collect{|el| el.split(/_and_/)}.flatten
|
112
|
-
end
|
113
|
-
# querystring hash from parent
|
114
|
-
def parent_hash
|
115
|
-
@parent ? @parent.to_hash : {}
|
116
|
-
end
|
117
|
-
def enhance_current_scope(scp, *args)
|
118
|
-
opts = args.extract_options!
|
119
|
-
check_scope(scp)
|
120
|
-
cache_key = "a#{Digest::MD5.hexdigest((args.sort + [scp]).to_s)}"
|
121
|
-
return instance_variable_get("@#{cache_key}") if instance_variable_defined?("@#{cache_key}")
|
122
|
-
return instance_variable_set("@#{cache_key}", self.class.class_factory(self.scopes[scp]).new(self.klass, scp, *args, opts.merge(:parent => self)))
|
123
|
-
end
|
124
|
-
# make sure we have a valid scope
|
125
|
-
def check_scope(scp)
|
126
|
-
raise ArgumentError, "Unknown scope #{scp}" unless self.scope?(scp.to_s)
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
end
|
131
|
-
|
132
|
-
end
|