mongo_mapper-rails3 0.7.0.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.
- data/.gitignore +10 -0
- data/Gemfile +15 -0
- data/LICENSE +20 -0
- data/README.rdoc +60 -0
- data/Rakefile +58 -0
- data/VERSION +1 -0
- data/bin/mmconsole +60 -0
- data/lib/mongo_mapper.rb +131 -0
- data/lib/mongo_mapper/document.rb +439 -0
- data/lib/mongo_mapper/embedded_document.rb +68 -0
- data/lib/mongo_mapper/plugins.rb +30 -0
- data/lib/mongo_mapper/plugins/associations.rb +106 -0
- data/lib/mongo_mapper/plugins/associations/base.rb +123 -0
- data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +30 -0
- data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +25 -0
- data/lib/mongo_mapper/plugins/associations/collection.rb +21 -0
- data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +50 -0
- data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +141 -0
- data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
- data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +120 -0
- data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +31 -0
- data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +23 -0
- data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +13 -0
- data/lib/mongo_mapper/plugins/associations/one_proxy.rb +68 -0
- data/lib/mongo_mapper/plugins/associations/proxy.rb +119 -0
- data/lib/mongo_mapper/plugins/callbacks.rb +87 -0
- data/lib/mongo_mapper/plugins/clone.rb +14 -0
- data/lib/mongo_mapper/plugins/descendants.rb +17 -0
- data/lib/mongo_mapper/plugins/dirty.rb +120 -0
- data/lib/mongo_mapper/plugins/equality.rb +24 -0
- data/lib/mongo_mapper/plugins/identity_map.rb +124 -0
- data/lib/mongo_mapper/plugins/inspect.rb +15 -0
- data/lib/mongo_mapper/plugins/keys.rb +310 -0
- data/lib/mongo_mapper/plugins/logger.rb +19 -0
- data/lib/mongo_mapper/plugins/pagination.rb +26 -0
- data/lib/mongo_mapper/plugins/pagination/proxy.rb +72 -0
- data/lib/mongo_mapper/plugins/protected.rb +46 -0
- data/lib/mongo_mapper/plugins/rails.rb +46 -0
- data/lib/mongo_mapper/plugins/serialization.rb +50 -0
- data/lib/mongo_mapper/plugins/validations.rb +88 -0
- data/lib/mongo_mapper/query.rb +130 -0
- data/lib/mongo_mapper/support.rb +217 -0
- data/lib/mongo_mapper/support/descendant_appends.rb +46 -0
- data/lib/mongo_mapper/support/find.rb +77 -0
- data/mongo_mapper-rails3.gemspec +208 -0
- data/performance/read_write.rb +52 -0
- data/specs.watchr +51 -0
- data/test/NOTE_ON_TESTING +1 -0
- data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +63 -0
- data/test/functional/associations/test_belongs_to_proxy.rb +101 -0
- data/test/functional/associations/test_in_array_proxy.rb +321 -0
- data/test/functional/associations/test_many_documents_as_proxy.rb +229 -0
- data/test/functional/associations/test_many_documents_proxy.rb +453 -0
- data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +176 -0
- data/test/functional/associations/test_many_embedded_proxy.rb +256 -0
- data/test/functional/associations/test_many_polymorphic_proxy.rb +302 -0
- data/test/functional/associations/test_one_proxy.rb +161 -0
- data/test/functional/test_associations.rb +44 -0
- data/test/functional/test_binary.rb +27 -0
- data/test/functional/test_callbacks.rb +81 -0
- data/test/functional/test_dirty.rb +163 -0
- data/test/functional/test_document.rb +1244 -0
- data/test/functional/test_embedded_document.rb +125 -0
- data/test/functional/test_identity_map.rb +508 -0
- data/test/functional/test_logger.rb +20 -0
- data/test/functional/test_modifiers.rb +252 -0
- data/test/functional/test_pagination.rb +93 -0
- data/test/functional/test_protected.rb +161 -0
- data/test/functional/test_string_id_compatibility.rb +67 -0
- data/test/functional/test_validations.rb +329 -0
- data/test/models.rb +232 -0
- data/test/support/custom_matchers.rb +55 -0
- data/test/support/timing.rb +16 -0
- data/test/test_helper.rb +59 -0
- data/test/unit/associations/test_base.rb +207 -0
- data/test/unit/associations/test_proxy.rb +105 -0
- data/test/unit/serializers/test_json_serializer.rb +189 -0
- data/test/unit/test_descendant_appends.rb +71 -0
- data/test/unit/test_document.rb +231 -0
- data/test/unit/test_dynamic_finder.rb +123 -0
- data/test/unit/test_embedded_document.rb +663 -0
- data/test/unit/test_keys.rb +169 -0
- data/test/unit/test_lint.rb +8 -0
- data/test/unit/test_mongo_mapper.rb +125 -0
- data/test/unit/test_pagination.rb +160 -0
- data/test/unit/test_plugins.rb +51 -0
- data/test/unit/test_query.rb +334 -0
- data/test/unit/test_rails.rb +123 -0
- data/test/unit/test_rails_compatibility.rb +57 -0
- data/test/unit/test_serialization.rb +51 -0
- data/test/unit/test_support.rb +362 -0
- data/test/unit/test_time_zones.rb +39 -0
- data/test/unit/test_validations.rb +557 -0
- metadata +344 -0
@@ -0,0 +1,19 @@
|
|
1
|
+
module MongoMapper
|
2
|
+
module Plugins
|
3
|
+
module Logger
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
def logger
|
8
|
+
MongoMapper.logger
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module InstanceMethods
|
13
|
+
def logger
|
14
|
+
self.class.logger
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module MongoMapper
|
2
|
+
module Plugins
|
3
|
+
module Pagination
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
def per_page
|
8
|
+
25
|
9
|
+
end
|
10
|
+
|
11
|
+
def paginate(options)
|
12
|
+
per_page = options.delete(:per_page) || self.per_page
|
13
|
+
page = options.delete(:page)
|
14
|
+
total_entries = count(options)
|
15
|
+
pagination = Pagination::Proxy.new(total_entries, page, per_page)
|
16
|
+
|
17
|
+
options.update(:limit => pagination.limit, :skip => pagination.skip)
|
18
|
+
pagination.subject = find_many(options)
|
19
|
+
pagination
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require 'mongo_mapper/plugins/pagination/proxy'
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module MongoMapper
|
2
|
+
module Plugins
|
3
|
+
module Pagination
|
4
|
+
class Proxy
|
5
|
+
instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?$|^send$|respond_to\?|proxy_|^object_id$)/ }
|
6
|
+
|
7
|
+
attr_accessor :subject
|
8
|
+
attr_reader :total_entries, :per_page, :current_page
|
9
|
+
alias limit per_page
|
10
|
+
|
11
|
+
def initialize(total_entries, current_page, per_page=nil)
|
12
|
+
@total_entries = total_entries.to_i
|
13
|
+
self.per_page = per_page
|
14
|
+
self.current_page = current_page
|
15
|
+
end
|
16
|
+
|
17
|
+
def total_pages
|
18
|
+
(total_entries / per_page.to_f).ceil
|
19
|
+
end
|
20
|
+
|
21
|
+
def out_of_bounds?
|
22
|
+
current_page > total_pages
|
23
|
+
end
|
24
|
+
|
25
|
+
def previous_page
|
26
|
+
current_page > 1 ? (current_page - 1) : nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def next_page
|
30
|
+
current_page < total_pages ? (current_page + 1) : nil
|
31
|
+
end
|
32
|
+
|
33
|
+
def skip
|
34
|
+
(current_page - 1) * per_page
|
35
|
+
end
|
36
|
+
alias offset skip # for will paginate support
|
37
|
+
|
38
|
+
def send(method, *args, &block)
|
39
|
+
if respond_to?(method)
|
40
|
+
super
|
41
|
+
else
|
42
|
+
subject.send(method, *args, &block)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def ===(other)
|
47
|
+
other === subject
|
48
|
+
end
|
49
|
+
|
50
|
+
def method_missing(name, *args, &block)
|
51
|
+
@subject.send(name, *args, &block)
|
52
|
+
end
|
53
|
+
|
54
|
+
def respond_to?(name, *args, &block)
|
55
|
+
super || @subject.respond_to?(name, *args, &block)
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
def per_page=(value)
|
60
|
+
value = 25 if value.blank?
|
61
|
+
@per_page = value.to_i
|
62
|
+
end
|
63
|
+
|
64
|
+
def current_page=(value)
|
65
|
+
value = value.to_i
|
66
|
+
value = 1 if value < 1
|
67
|
+
@current_page = value
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module MongoMapper
|
2
|
+
module Plugins
|
3
|
+
module Protected
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
module ClassMethods
|
6
|
+
def attr_protected(*attrs)
|
7
|
+
self.write_inheritable_attribute(:attr_protected, Set.new(attrs) + (protected_attributes || []))
|
8
|
+
end
|
9
|
+
|
10
|
+
def protected_attributes
|
11
|
+
self.read_inheritable_attribute(:attr_protected)
|
12
|
+
end
|
13
|
+
|
14
|
+
def key(*args)
|
15
|
+
key = super
|
16
|
+
attr_protected key.name.to_sym if key.options[:protected]
|
17
|
+
key
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module InstanceMethods
|
22
|
+
def assign(attrs={})
|
23
|
+
super(filter_protected_attrs(attrs))
|
24
|
+
end
|
25
|
+
|
26
|
+
def update_attributes(attrs={})
|
27
|
+
super(filter_protected_attrs(attrs))
|
28
|
+
end
|
29
|
+
|
30
|
+
def update_attributes!(attrs={})
|
31
|
+
super(filter_protected_attrs(attrs))
|
32
|
+
end
|
33
|
+
|
34
|
+
def protected_attributes
|
35
|
+
self.class.protected_attributes
|
36
|
+
end
|
37
|
+
|
38
|
+
protected
|
39
|
+
def filter_protected_attrs(attrs)
|
40
|
+
return attrs if protected_attributes.blank?
|
41
|
+
attrs.dup.delete_if { |key, val| protected_attributes.include?(key.to_sym) }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module MongoMapper
|
2
|
+
module Plugins
|
3
|
+
module Rails
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
module InstanceMethods
|
6
|
+
def to_param
|
7
|
+
id.to_s
|
8
|
+
end
|
9
|
+
|
10
|
+
def new_record?
|
11
|
+
new?
|
12
|
+
end
|
13
|
+
|
14
|
+
def read_attribute(name)
|
15
|
+
self[name]
|
16
|
+
end
|
17
|
+
|
18
|
+
def read_attribute_before_typecast(name)
|
19
|
+
read_key_before_typecast(name)
|
20
|
+
end
|
21
|
+
|
22
|
+
def write_attribute(name, value)
|
23
|
+
self[name] = value
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
module ClassMethods
|
28
|
+
def has_one(*args)
|
29
|
+
one(*args)
|
30
|
+
end
|
31
|
+
|
32
|
+
def has_many(*args)
|
33
|
+
many(*args)
|
34
|
+
end
|
35
|
+
|
36
|
+
def column_names
|
37
|
+
keys.keys
|
38
|
+
end
|
39
|
+
|
40
|
+
def human
|
41
|
+
self.name.demodulize.titleize
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'active_support/json'
|
2
|
+
|
3
|
+
module MongoMapper
|
4
|
+
module Plugins
|
5
|
+
module Serialization
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
include ActiveModel::Serializers::JSON
|
10
|
+
# Re-include this here otherwise we get run over by ActiveModel serialization
|
11
|
+
include SerializableHash
|
12
|
+
extend FromJson
|
13
|
+
end
|
14
|
+
|
15
|
+
module SerializableHash
|
16
|
+
def serializable_hash options={}
|
17
|
+
options ||= {}
|
18
|
+
unless options[:only]
|
19
|
+
methods = [options.delete(:methods)].flatten.compact
|
20
|
+
methods << :id
|
21
|
+
options[:methods] = methods.uniq
|
22
|
+
end
|
23
|
+
|
24
|
+
except = [options.delete(:except)].flatten.compact
|
25
|
+
except << :_id
|
26
|
+
options[:except] = except
|
27
|
+
|
28
|
+
hash = super(options)
|
29
|
+
hash.each do |key, value|
|
30
|
+
if value.is_a?(Array)
|
31
|
+
hash[key] = value.map do |item|
|
32
|
+
item.respond_to?(:serializable_hash) ? item.serializable_hash(options) : item
|
33
|
+
end
|
34
|
+
elsif value.respond_to?(:serializable_hash)
|
35
|
+
hash[key] = value.serializable_hash(options)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
module FromJson
|
42
|
+
def from_json(json)
|
43
|
+
self.attributes = ActiveSupport::JSON.decode(json)
|
44
|
+
self
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module MongoMapper
|
2
|
+
module Plugins
|
3
|
+
module Validations
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
included do
|
6
|
+
include ::ActiveModel::Validations
|
7
|
+
extend FixValidationKeyNames
|
8
|
+
extend LifecycleValidationMethods
|
9
|
+
end
|
10
|
+
|
11
|
+
module DocumentMacros
|
12
|
+
def validates_uniqueness_of(attrs, ops={})
|
13
|
+
# add_validations(args, MongoMapper::Plugins::Validations::ValidatesUniquenessOf)
|
14
|
+
validates_with ValidatesUniquenessOf, {:attributes => attrs}.merge(ops)
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
module FixValidationKeyNames
|
21
|
+
def validates_inclusion_of(*args,&b)
|
22
|
+
if args.last.kind_of?(Hash)
|
23
|
+
args.last[:in] ||= args.last[:within]
|
24
|
+
end
|
25
|
+
super(*args,&b)
|
26
|
+
end
|
27
|
+
def validates_exclusion_of(*args,&b)
|
28
|
+
if args.last.kind_of?(Hash)
|
29
|
+
args.last[:in] ||= args.last[:within]
|
30
|
+
end
|
31
|
+
super(*args,&b)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
module LifecycleValidationMethods
|
36
|
+
def validate_on_create(name)
|
37
|
+
validate(name, :on => :create)
|
38
|
+
end
|
39
|
+
def validate_on_update(name)
|
40
|
+
validate(name, :on => :update)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class ValidatesUniquenessOf < ActiveModel::EachValidator
|
45
|
+
attr_accessor :scope, :allow_blank, :allow_nil, :attributes, :case_sensitive
|
46
|
+
def case_sensitive
|
47
|
+
@case_sensitive.nil? ? true : @case_sensitive
|
48
|
+
end
|
49
|
+
|
50
|
+
def initialize(ops)
|
51
|
+
ops.each { |k,v| send("#{k}=",v) }
|
52
|
+
end
|
53
|
+
|
54
|
+
def validate(record)
|
55
|
+
[attributes].flatten.each do |attribute|
|
56
|
+
record.errors.add(*message(record,attribute)) unless valid?(record,attribute)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def valid?(instance,attribute)
|
61
|
+
value = instance[attribute]
|
62
|
+
return true if allow_blank && value.blank?
|
63
|
+
return true if allow_nil && value.nil?
|
64
|
+
base_conditions = case_sensitive ? {attribute => value} : {}
|
65
|
+
doc = instance.class.first(base_conditions.merge(scope_conditions(instance)).merge(where_conditions(instance,attribute)))
|
66
|
+
doc.nil? || instance._id == doc._id
|
67
|
+
end
|
68
|
+
|
69
|
+
def message(instance,attribute)
|
70
|
+
[attribute,"has already been taken"]
|
71
|
+
end
|
72
|
+
|
73
|
+
def scope_conditions(instance)
|
74
|
+
return {} unless scope
|
75
|
+
Array(scope).inject({}) do |conditions, key|
|
76
|
+
conditions.merge(key => instance[key])
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def where_conditions(instance, attribute)
|
81
|
+
conditions = {}
|
82
|
+
conditions[attribute] = /#{instance[attribute].to_s}/i unless case_sensitive
|
83
|
+
conditions
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
module MongoMapper
|
2
|
+
# IMPORTANT
|
3
|
+
# This class is private to MongoMapper and should not be considered part of MongoMapper's public API.
|
4
|
+
#
|
5
|
+
class Query
|
6
|
+
OptionKeys = [:fields, :select, :skip, :offset, :limit, :sort, :order]
|
7
|
+
|
8
|
+
attr_reader :model
|
9
|
+
|
10
|
+
def initialize(model, options)
|
11
|
+
raise ArgumentError, "Options must be a hash" unless options.is_a?(Hash)
|
12
|
+
@model, @options, @conditions, @original_options = model, {}, {}, options
|
13
|
+
separate_options_and_conditions
|
14
|
+
add_sci_condition
|
15
|
+
end
|
16
|
+
|
17
|
+
def criteria
|
18
|
+
to_criteria(@conditions)
|
19
|
+
end
|
20
|
+
|
21
|
+
def options
|
22
|
+
fields = @options[:fields] || @options[:select]
|
23
|
+
skip = @options[:skip] || @options[:offset] || 0
|
24
|
+
limit = @options[:limit] || 0
|
25
|
+
sort = @options[:sort] || normalized_sort(@options[:order])
|
26
|
+
|
27
|
+
{:fields => to_fields(fields), :skip => skip.to_i, :limit => limit.to_i, :sort => sort}
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_a
|
31
|
+
[criteria, options]
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
def separate_options_and_conditions
|
36
|
+
@original_options.each_pair do |key, value|
|
37
|
+
key = key.respond_to?(:to_sym) ? key.to_sym : key
|
38
|
+
|
39
|
+
if OptionKeys.include?(key)
|
40
|
+
@options[key] = value
|
41
|
+
elsif key == :conditions
|
42
|
+
@conditions.update(value)
|
43
|
+
else
|
44
|
+
@conditions[key] = value
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# adds _type single collection inheritance scope for models that need it
|
50
|
+
def add_sci_condition
|
51
|
+
@conditions[:_type] = model.to_s if model.single_collection_inherited?
|
52
|
+
end
|
53
|
+
|
54
|
+
def modifier?(field)
|
55
|
+
field.to_s =~ /^\$/
|
56
|
+
end
|
57
|
+
|
58
|
+
def symbol_operator?(object)
|
59
|
+
object.respond_to?(:field, :operator)
|
60
|
+
end
|
61
|
+
|
62
|
+
def to_criteria(conditions, parent_key=nil)
|
63
|
+
criteria = {}
|
64
|
+
|
65
|
+
conditions.each_pair do |key, value|
|
66
|
+
key = normalized_key(key)
|
67
|
+
|
68
|
+
if model.object_id_key?(key) && value.is_a?(String)
|
69
|
+
value = Mongo::ObjectID.from_string(value)
|
70
|
+
end
|
71
|
+
|
72
|
+
if symbol_operator?(key)
|
73
|
+
value = {"$#{key.operator}" => value}
|
74
|
+
key = normalized_key(key.field)
|
75
|
+
end
|
76
|
+
|
77
|
+
criteria[key] = normalized_value(key, value)
|
78
|
+
end
|
79
|
+
|
80
|
+
criteria
|
81
|
+
end
|
82
|
+
|
83
|
+
def to_fields(fields)
|
84
|
+
return if fields.blank?
|
85
|
+
|
86
|
+
if fields.respond_to?(:flatten, :compact)
|
87
|
+
fields.flatten.compact
|
88
|
+
else
|
89
|
+
fields.split(',').map { |field| field.strip }
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def to_order(field, direction=nil)
|
94
|
+
direction ||= 'ASC'
|
95
|
+
direction = direction.upcase == 'ASC' ? 1 : -1
|
96
|
+
[field.to_s, direction]
|
97
|
+
end
|
98
|
+
|
99
|
+
def normalized_key(field)
|
100
|
+
field.to_s == 'id' ? :_id : field
|
101
|
+
end
|
102
|
+
|
103
|
+
def normalized_value(field, value)
|
104
|
+
case value
|
105
|
+
when Array
|
106
|
+
modifier?(field) ? value : {'$in' => value}
|
107
|
+
when Hash
|
108
|
+
to_criteria(value, field)
|
109
|
+
when Time
|
110
|
+
value.utc
|
111
|
+
else
|
112
|
+
value
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def normalized_sort(sort)
|
117
|
+
return if sort.blank?
|
118
|
+
|
119
|
+
if sort.respond_to?(:all?) && sort.all? { |s| symbol_operator?(s) }
|
120
|
+
sort.map { |s| to_order(s.field, s.operator) }
|
121
|
+
elsif symbol_operator?(sort)
|
122
|
+
[to_order(sort.field, sort.operator)]
|
123
|
+
else
|
124
|
+
sort.split(',').map do |str|
|
125
|
+
to_order(*str.strip.split(' '))
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|