eco-helpers 3.0.31 → 3.0.33
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +24 -2
- data/lib/eco/api/common/loaders/config/workflow/mailer.rb +13 -11
- data/lib/eco/api/common/loaders/use_case/cli_identify.rb +3 -0
- data/lib/eco/api/common/version_patches/exception.rb +10 -2
- data/lib/eco/api/microcases/people/fetch/with_each.rb +9 -2
- data/lib/eco/api/organization/people/multiple_search_results.rb +42 -36
- data/lib/eco/api/organization/people/similarity.rb +226 -224
- data/lib/eco/api/session/batch/job.rb +1 -0
- data/lib/eco/api/usecases/cli/dsl.rb +0 -1
- data/lib/eco/api/usecases/cli/option.rb +1 -1
- data/lib/eco/api/usecases/default_cases/create_case.rb +3 -3
- data/lib/eco/api/usecases/default_cases/delete_sync_case.rb +2 -2
- data/lib/eco/api/usecases/default_cases/delete_trans_case.rb +3 -3
- data/lib/eco/api/usecases/default_cases/hris_case.rb +10 -9
- data/lib/eco/api/usecases/default_cases/to_csv_case.rb +10 -10
- data/lib/eco/api/usecases/default_cases/to_csv_detailed_case.rb +50 -50
- data/lib/eco/api/usecases/default_cases/update_case.rb +3 -3
- data/lib/eco/cli/config/use_cases/active_case.rb +9 -0
- data/lib/eco/cli/config/use_cases/case_config.rb +27 -0
- data/lib/eco/cli/config/use_cases.rb +2 -15
- data/lib/eco/cli_default/input.rb +6 -0
- data/lib/eco/cli_default/usecases.rb +1 -1
- data/lib/eco/language/auxiliar_logger.rb +1 -1
- data/lib/eco/language/delegation/delegating_blank.rb +4 -16
- data/lib/eco/language/delegation/delegating_missing_const.rb +1 -1
- data/lib/eco/language/methods/call_detector.rb +4 -8
- data/lib/eco/language/methods/dsl_able.rb +29 -33
- data/lib/eco/language/methods/instance_method_helpers.rb +38 -0
- data/lib/eco/language/methods.rb +1 -0
- data/lib/eco/language.rb +1 -1
- data/lib/eco/version.rb +1 -1
- metadata +5 -2
@@ -137,16 +137,16 @@ class Eco::API::UseCases::DefaultCases::ToCsvCase < Eco::API::Common::Loaders::U
|
|
137
137
|
|
138
138
|
def nice_header_maps
|
139
139
|
@nice_header_maps ||= {
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
140
|
+
'policy_group_ids' => 'User Group(s)',
|
141
|
+
'email' => 'Email',
|
142
|
+
'name' => 'Name',
|
143
|
+
'supervisor_id' => 'Manager ID',
|
144
|
+
'filter_tags' => 'Locations',
|
145
|
+
'default_tag' => 'Default Location',
|
146
|
+
'id' => 'ecoPortal ID',
|
147
|
+
'external_id' => 'Reference ID (ext_id)',
|
148
|
+
'login_provider_ids' => 'Login Methods',
|
149
|
+
'landing_page_id' => 'Landing Page ID'
|
150
150
|
}
|
151
151
|
end
|
152
152
|
end
|
@@ -1,11 +1,11 @@
|
|
1
1
|
class Eco::API::UseCases::DefaultCases::ToCsvDetailedCase < Eco::API::UseCases::DefaultCases::ToCsvCase
|
2
|
-
name
|
2
|
+
name 'to-csv-detailed'
|
3
3
|
type :export
|
4
4
|
|
5
5
|
private
|
6
6
|
|
7
7
|
def to_row(person)
|
8
|
-
data = super
|
8
|
+
data = super
|
9
9
|
data << person_supervisor(person)
|
10
10
|
data += user_abilities(person)
|
11
11
|
data += user_permissions_custom(person) if options.dig(:export, :options, :permissions_custom)
|
@@ -17,18 +17,18 @@ class Eco::API::UseCases::DefaultCases::ToCsvDetailedCase < Eco::API::UseCases::
|
|
17
17
|
|
18
18
|
def person_supervisor(person)
|
19
19
|
session.micro.with_supervisor(person.supervisor_id, people) do |supervisor|
|
20
|
-
return supervisor ? supervisor.name :
|
20
|
+
return supervisor ? supervisor.name : ''
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
24
|
def user_abilities(person)
|
25
25
|
account_abilities = (person.account && person.account.permissions_merged) || {}
|
26
|
-
abilities.map {|key| account_abilities[key] ||
|
26
|
+
abilities.map {|key| account_abilities[key] || 'no access'}
|
27
27
|
end
|
28
28
|
|
29
29
|
def user_permissions_custom(person)
|
30
30
|
account_abilities = (person.account && person.account.permissions_custom) || {}
|
31
|
-
abilities.map {|key| account_abilities[key] ||
|
31
|
+
abilities.map {|key| account_abilities[key] || 'no access'}
|
32
32
|
end
|
33
33
|
|
34
34
|
def user_preferences(person)
|
@@ -38,17 +38,17 @@ class Eco::API::UseCases::DefaultCases::ToCsvDetailedCase < Eco::API::UseCases::
|
|
38
38
|
|
39
39
|
def spot_header(person = people.first)
|
40
40
|
super(person) do |header|
|
41
|
-
header <<
|
41
|
+
header << 'Supervisor Name'
|
42
42
|
header += abilities_header
|
43
|
-
header += abilities_header(
|
44
|
-
header <<
|
43
|
+
header += abilities_header('custom') if options.dig(:export, :options, :permissions_custom)
|
44
|
+
header << 'Landing Page'
|
45
45
|
header += preferences
|
46
46
|
header
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
50
|
def keys(entry)
|
51
|
-
super
|
51
|
+
super | ['freemium']
|
52
52
|
end
|
53
53
|
|
54
54
|
def login_providers
|
@@ -66,52 +66,52 @@ class Eco::API::UseCases::DefaultCases::ToCsvDetailedCase < Eco::API::UseCases::
|
|
66
66
|
end
|
67
67
|
|
68
68
|
def preferences
|
69
|
-
@preferences ||= [
|
70
|
-
|
71
|
-
|
72
|
-
|
69
|
+
@preferences ||= %w[
|
70
|
+
show_sidebar, show_shortcuts, show_coming_soon, show_recently_visited_forms,
|
71
|
+
show_tasks, show_task_bubbles,
|
72
|
+
kiosk_enabled
|
73
73
|
]
|
74
74
|
end
|
75
75
|
|
76
76
|
def nice_header_maps
|
77
77
|
@nice_header_maps ||= super.merge({
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
78
|
+
'landing_page_id' => 'Landing Page ID',
|
79
|
+
'show_sidebar' => '(pref) Sidebar Open?',
|
80
|
+
'show_shortcuts' => '(pref) Link to Registers?',
|
81
|
+
'show_coming_soon' => '(pref) Coming Soon List?',
|
82
|
+
'show_recently_visited_forms' => '(pref) Recently Visited Forms List?',
|
83
|
+
'show_tasks' => '(pref) Tasks List?',
|
84
|
+
'show_task_bubbles' => '(pref) Task Count Bubbles',
|
85
|
+
'kiosk_enabled' => 'Kiosk User?',
|
86
|
+
'freemium' => 'Freemium User?',
|
87
|
+
'files' => '(able) on Files',
|
88
|
+
'reports' => '(able) on Report Structures',
|
89
|
+
'data' => '(able) on Data (hours, datasets)',
|
90
|
+
'organization' => '(able) on Organization Config',
|
91
|
+
'pages' => '(able) on Page/Entries',
|
92
|
+
'page_editor' => '(able) page Editor Level',
|
93
|
+
'registers' => '(able) on Registers',
|
94
|
+
'tasks' => '(able) on Tasks',
|
95
|
+
'person_core' => '(able) on People',
|
96
|
+
'person_core_create' => '(able) Create People?',
|
97
|
+
'person_core_edit' => '(able) Edit People?',
|
98
|
+
'person_details' => '(able) on People Schema Details',
|
99
|
+
'person_account' => '(able) on Users',
|
100
|
+
'person_abilities' => "(able) on Users' Abilities",
|
101
|
+
'custom_files' => '(min) on Files',
|
102
|
+
'custom_reports' => '(min) on Report Structures',
|
103
|
+
'custom_data' => '(min) on Data (hours, datasets)',
|
104
|
+
'custom_organization' => '(min) on Organization Config',
|
105
|
+
'custom_pages' => '(min) on Page/Entries',
|
106
|
+
'custom_page_editor' => '(min) page Editor Level',
|
107
|
+
'custom_registers' => '(min) on Registers',
|
108
|
+
'custom_tasks' => '(min) on Tasks',
|
109
|
+
'custom_person_core' => '(min) on People',
|
110
|
+
'custom_person_core_create' => '(min) Create People?',
|
111
|
+
'custom_person_core_edit' => '(min) Edit People?',
|
112
|
+
'custom_person_details' => '(min) on People Schema Details',
|
113
|
+
'custom_person_account' => '(min) on Users',
|
114
|
+
'custom_person_abilities' => "(min) on Users' Abilities"
|
115
115
|
})
|
116
116
|
end
|
117
117
|
end
|
@@ -1,10 +1,10 @@
|
|
1
1
|
class Eco::API::UseCases::DefaultCases::UpdateCase < Eco::API::Common::Loaders::UseCase
|
2
|
-
name
|
2
|
+
name 'update'
|
3
3
|
type :sync
|
4
4
|
|
5
5
|
def main(entries, people, session, options, usecase)
|
6
|
-
update = session.new_job(
|
7
|
-
supers = session.new_job(
|
6
|
+
update = session.new_job('main', 'update', :update, usecase)
|
7
|
+
supers = session.new_job('post', 'supers', :update, usecase, :core)
|
8
8
|
|
9
9
|
micro.with_each_present(entries, people, options, log_starter: true) do |entry, person|
|
10
10
|
update.add(person)
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Eco
|
2
|
+
class CLI
|
3
|
+
class Config
|
4
|
+
class UseCases
|
5
|
+
CaseConfig = Struct.new(
|
6
|
+
:cases_config,
|
7
|
+
:option,
|
8
|
+
:type,
|
9
|
+
:description,
|
10
|
+
:casename,
|
11
|
+
:callback
|
12
|
+
) do
|
13
|
+
def add_option(arg, desc = nil, &block)
|
14
|
+
core_config.options_set.add(arg, desc, namespace: option, &block)
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def core_config
|
21
|
+
cases_config.core_config
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require_relative 'use_cases/case_config'
|
2
|
+
require_relative 'use_cases/active_case'
|
1
3
|
module Eco
|
2
4
|
class CLI
|
3
5
|
class Config
|
@@ -5,21 +7,6 @@ module Eco
|
|
5
7
|
include Eco::CLI::Config::Help
|
6
8
|
attr_reader :core_config
|
7
9
|
|
8
|
-
CaseConfig = Struct.new(:cases_config, :option, :type, :description, :casename, :callback) do
|
9
|
-
def add_option(arg, desc = nil, &block)
|
10
|
-
core_config.options_set.add(arg, desc, namespace: option, &block)
|
11
|
-
self
|
12
|
-
end
|
13
|
-
|
14
|
-
private
|
15
|
-
|
16
|
-
def core_config
|
17
|
-
cases_config.core_config
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
ActiveCase = Struct.new(:index, :option, :callback)
|
22
|
-
|
23
10
|
def initialize(core_config:)
|
24
11
|
@core_config = core_config
|
25
12
|
@linked_cases = {}
|
@@ -68,6 +68,12 @@ class Eco::CliDefault::Input < Eco::API::Common::Loaders::CliConfig
|
|
68
68
|
file = file.select do |f|
|
69
69
|
ext.any? {|e| File.extname(f) == e}
|
70
70
|
end.tap do |files|
|
71
|
+
session.log(:general) {
|
72
|
+
files_msg = 'Using these as input files:'
|
73
|
+
files_msg << "\n * "
|
74
|
+
files_msg << files.join("\n * ")
|
75
|
+
}
|
76
|
+
|
71
77
|
next unless files.empty?
|
72
78
|
|
73
79
|
session.log(:error) {
|
@@ -1,5 +1,5 @@
|
|
1
1
|
ASSETS.cli.config do |cnf| # rubocop:disable Metrics/BlockLength
|
2
|
-
cnf.usecases do |cases|
|
2
|
+
cnf.usecases do |cases|
|
3
3
|
desc = 'It exports to a CSV the (filtered) people'
|
4
4
|
cases.add('-people-to-csv', :export, desc) do |people, session, options|
|
5
5
|
file = SCR.get_file('-people-to-csv', required: true, should_exist: false)
|
@@ -29,7 +29,7 @@ module Eco
|
|
29
29
|
return unless logger
|
30
30
|
|
31
31
|
levels = levels.compact.uniq.map(&:to_sym)
|
32
|
-
levels.unshift(:
|
32
|
+
levels.unshift(:debug) if levels.include?(:general) && levels.length == 1
|
33
33
|
|
34
34
|
levels.uniq.each do |level|
|
35
35
|
next unless logger.respond_to?(:level, true)
|
@@ -10,6 +10,8 @@ module Eco::Language::Delegation
|
|
10
10
|
super
|
11
11
|
|
12
12
|
base.include DelegatingMissing
|
13
|
+
base.send :include, Eco::Language::Methods::InstanceMethodHelpers
|
14
|
+
|
13
15
|
base.extend ClassMethods
|
14
16
|
base.inheritable_class_vars :_delegating_blank
|
15
17
|
end
|
@@ -70,7 +72,7 @@ module Eco::Language::Delegation
|
|
70
72
|
private
|
71
73
|
|
72
74
|
def method_added(method_name)
|
73
|
-
return super if (@installing ||= false)
|
75
|
+
return super if (@installing ||= false) # rubocop:disable Style/ParenthesesAroundCondition
|
74
76
|
|
75
77
|
method_name = method_name.to_sym
|
76
78
|
return super unless delegating_blank?(method_name)
|
@@ -96,7 +98,7 @@ module Eco::Language::Delegation
|
|
96
98
|
|
97
99
|
return unless instance_method?(base, name: method_name, include_private: true)
|
98
100
|
|
99
|
-
method_was_inherited =
|
101
|
+
method_was_inherited = instance_inherited_method?(base, name: method_name)
|
100
102
|
original_method = :"delegated_blank_original_#{method_name}"
|
101
103
|
|
102
104
|
return if instance_method?(base, name: original_method, include_private: true, inherited: false)
|
@@ -124,20 +126,6 @@ module Eco::Language::Delegation
|
|
124
126
|
base.define_method(method_name, &method_def)
|
125
127
|
end
|
126
128
|
|
127
|
-
def instance_method?(base = self, name:, include_private: false, inherited: true)
|
128
|
-
return true if base.method_defined?(name, inherited)
|
129
|
-
return false unless include_private
|
130
|
-
|
131
|
-
base.private_instance_methods(inherited).include?(name.to_sym)
|
132
|
-
end
|
133
|
-
|
134
|
-
def inherited_method?(base = self, name:)
|
135
|
-
return false if base.public_instance_methods(false).include?(name.to_sym)
|
136
|
-
return false if base.private_instance_methods(false).include?(name.to_sym)
|
137
|
-
|
138
|
-
true
|
139
|
-
end
|
140
|
-
|
141
129
|
def sym_or_string?(value)
|
142
130
|
return false unless value.is_a?(Symbol) || value.is_a?(String)
|
143
131
|
return false if value.to_s.strip.empty?
|
@@ -42,7 +42,7 @@ module Eco::Language::Delegation
|
|
42
42
|
def initialize(...)
|
43
43
|
super if defined?(super)
|
44
44
|
|
45
|
-
delegated_class.tap do
|
45
|
+
delegated_class.tap do
|
46
46
|
next unless (target = self.class.delegating_missing_target(self))
|
47
47
|
|
48
48
|
self.class.delegated_class target.class
|
@@ -1,11 +1,7 @@
|
|
1
|
-
module Eco
|
2
|
-
module
|
3
|
-
|
4
|
-
|
5
|
-
def called_via?(klass, sym)
|
6
|
-
klass == method(sym).owner
|
7
|
-
end
|
8
|
-
end
|
1
|
+
module Eco::Language::Methods
|
2
|
+
module CallDetector
|
3
|
+
def called_via?(klass, sym)
|
4
|
+
klass == method(sym).owner
|
9
5
|
end
|
10
6
|
end
|
11
7
|
end
|
@@ -1,41 +1,37 @@
|
|
1
|
-
module Eco
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
def evaluate(*args, **kargs, &block)
|
16
|
-
return unless block_given?
|
1
|
+
module Eco::Language::Methods
|
2
|
+
# Adds #evaluate, which will run `&block` where `DslAble` has been included.
|
3
|
+
# @note
|
4
|
+
# 1. If a method is missing on the evaluation object, it will re-try it on
|
5
|
+
# on the block context.
|
6
|
+
# 2. **Override behaviour**: the above gives precedence to
|
7
|
+
# methods defined in the context of the object that evaluates,
|
8
|
+
# over those in the block context.
|
9
|
+
module DslAble
|
10
|
+
# It runs the `block` within this object context
|
11
|
+
# @note if the object misses any method, redirects the method to the
|
12
|
+
# original evaluate caller.
|
13
|
+
def evaluate(*args, **kargs, &block)
|
14
|
+
return unless block_given?
|
17
15
|
|
18
|
-
|
16
|
+
@self_before_evaluate = eval('self', block.binding, __FILE__, __LINE__)
|
19
17
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
18
|
+
instance_exec(*args, **kargs, &block).tap do
|
19
|
+
@self_before_evaluate = nil
|
20
|
+
end
|
21
|
+
end
|
24
22
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
23
|
+
# When it's the case, redirect to the original `evaluate` caller
|
24
|
+
# @see https://www.dan-manges.com/blog/ruby-dsls-instance-eval-with-delegation
|
25
|
+
def method_missing(method, *args, **kargs, &block)
|
26
|
+
super unless @self_before_evaluate
|
29
27
|
|
30
|
-
|
31
|
-
|
28
|
+
@self_before_evaluate.send(method, *args, **kargs, &block)
|
29
|
+
end
|
32
30
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
end
|
38
|
-
end
|
31
|
+
# This allows to capture a method using `name` method.
|
32
|
+
# @note that for a Dsl this is not necessary
|
33
|
+
def respond_to_missing?(name, include_private = false)
|
34
|
+
super
|
39
35
|
end
|
40
36
|
end
|
41
37
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Eco::Language::Methods
|
2
|
+
# Helpers to scope instance methods.
|
3
|
+
module InstanceMethodHelpers
|
4
|
+
class << self
|
5
|
+
def included(base)
|
6
|
+
super
|
7
|
+
|
8
|
+
base.extend ClassMethods
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
private
|
14
|
+
|
15
|
+
def unless_instance_method(base = self, name:, include_private: true, inherited: true)
|
16
|
+
return false if instance_method?(base, name: name, include_private: include_private, inherited: inherited)
|
17
|
+
|
18
|
+
yield if block_given?
|
19
|
+
|
20
|
+
true
|
21
|
+
end
|
22
|
+
|
23
|
+
def instance_method?(base = self, name:, include_private: false, inherited: true)
|
24
|
+
return true if base.method_defined?(name, inherited)
|
25
|
+
return false unless include_private
|
26
|
+
|
27
|
+
base.private_instance_methods(inherited).include?(name.to_sym)
|
28
|
+
end
|
29
|
+
|
30
|
+
def instance_inherited_method?(base = self, name:)
|
31
|
+
return false if base.public_instance_methods(false).include?(name.to_sym)
|
32
|
+
return false if base.private_instance_methods(false).include?(name.to_sym)
|
33
|
+
|
34
|
+
true
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/eco/language/methods.rb
CHANGED
data/lib/eco/language.rb
CHANGED
@@ -4,8 +4,8 @@ module Eco
|
|
4
4
|
end
|
5
5
|
|
6
6
|
require_relative 'language/strings'
|
7
|
-
require_relative 'language/klass'
|
8
7
|
require_relative 'language/methods'
|
8
|
+
require_relative 'language/klass'
|
9
9
|
require_relative 'language/models'
|
10
10
|
require_relative 'language/auxiliar_logger'
|
11
11
|
require_relative 'language/basic_logger'
|
data/lib/eco/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: eco-helpers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0.
|
4
|
+
version: 3.0.33
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Oscar Segura
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-04-
|
11
|
+
date: 2025-04-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: byebug
|
@@ -932,6 +932,8 @@ files:
|
|
932
932
|
- lib/eco/cli/config/input.rb
|
933
933
|
- lib/eco/cli/config/options_set.rb
|
934
934
|
- lib/eco/cli/config/use_cases.rb
|
935
|
+
- lib/eco/cli/config/use_cases/active_case.rb
|
936
|
+
- lib/eco/cli/config/use_cases/case_config.rb
|
935
937
|
- lib/eco/cli/scripting.rb
|
936
938
|
- lib/eco/cli/scripting/args_helpers.rb
|
937
939
|
- lib/eco/cli/scripting/argument.rb
|
@@ -1028,6 +1030,7 @@ files:
|
|
1028
1030
|
- lib/eco/language/methods.rb
|
1029
1031
|
- lib/eco/language/methods/call_detector.rb
|
1030
1032
|
- lib/eco/language/methods/dsl_able.rb
|
1033
|
+
- lib/eco/language/methods/instance_method_helpers.rb
|
1031
1034
|
- lib/eco/language/models.rb
|
1032
1035
|
- lib/eco/language/models/class_helpers.rb
|
1033
1036
|
- lib/eco/language/models/collection.rb
|