tramway-core 1.17.2.1 → 1.17.2.2
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/README.md +4 -2
- data/app/decorators/tramway/core/application_decorator.rb +0 -1
- data/app/decorators/tramway/core/associations/class_helper.rb +1 -0
- data/app/decorators/tramway/core/associations/object_helper.rb +1 -1
- data/app/decorators/tramway/core/delegating/class_helper.rb +2 -0
- data/app/forms/tramway/core/application_form.rb +83 -146
- data/app/forms/tramway/core/application_forms/association_object_helpers.rb +31 -0
- data/app/forms/tramway/core/application_forms/constant_class_actions.rb +7 -0
- data/app/forms/tramway/core/application_forms/constant_object_actions.rb +13 -0
- data/app/forms/tramway/core/application_forms/properties_object_helper.rb +23 -0
- data/app/forms/tramway/core/extendable_form.rb +3 -70
- data/app/forms/tramway/core/extendable_forms_helpers/class_builder.rb +34 -0
- data/app/forms/tramway/core/extendable_forms_helpers/ignored_properties_helper.rb +11 -0
- data/app/forms/tramway/core/extendable_forms_helpers/more_properties_helper.rb +27 -0
- data/app/forms/tramway/core/extendable_forms_helpers/properties_helper.rb +16 -0
- data/app/forms/tramway/core/extendable_forms_helpers/submit/class_helpers.rb +18 -0
- data/app/forms/tramway/core/extendable_forms_helpers/submit/object_helpers.rb +7 -0
- data/app/forms/tramway/core/extendable_forms_helpers/validators.rb +40 -0
- data/app/helpers/tramway/core/copy_to_clipboard_helper.rb +6 -10
- data/app/helpers/tramway/core/title_helper.rb +17 -22
- data/app/models/tramway/core/application_record.rb +38 -40
- data/app/uploaders/image_defaults.rb +2 -1
- data/app/uploaders/photo_uploader.rb +8 -8
- data/config/initializers/plurals.rb +2 -2
- data/lib/tramway/collection.rb +4 -6
- data/lib/tramway/collections.rb +4 -0
- data/lib/tramway/collections/helper.rb +15 -14
- data/lib/tramway/core.rb +19 -23
- data/lib/tramway/core/engine.rb +4 -8
- data/lib/tramway/core/generators.rb +4 -0
- data/lib/tramway/core/generators/install_generator.rb +17 -17
- data/lib/tramway/core/version.rb +1 -1
- data/lib/tramway/error.rb +12 -1
- metadata +17 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3c612a0122da3218a86e61b973beff51f378e14352fd424489130039694f82f8
|
4
|
+
data.tar.gz: 07d47a9b6e995469f7b500e34b21f705cc24ce1e4aede1e946ace36f5ddebb28
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8b275c112e32864152637a34c283677de289fc2fb5e79123fd15f149656e0d3741c1b7768e06d441004927e4fe5db0f4af2a744a55e6fdc58fe210227e1b7ce7
|
7
|
+
data.tar.gz: 350ace536d11005778f241370a3179f5f51f9078d8822ca4e80955aeb0ffb93edbafc64e55d9635d0cba4e4cc4ef8b3fd6f3aa205a7171542b25e6500c82d281
|
data/README.md
CHANGED
@@ -203,8 +203,10 @@ Tramway::Admin.set_singleton_models Organization, project: :organization # now y
|
|
203
203
|
* models - часто используемые в моделях слова
|
204
204
|
* state_machines - локализация состояний
|
205
205
|
|
206
|
-
##
|
207
|
-
|
206
|
+
## Contributors
|
207
|
+
|
208
|
+
* [Pavel Kalashnikov](https://github.com/kalashnikovisme)
|
209
|
+
* [moshinaan](https://github.com/moshinaan)
|
208
210
|
|
209
211
|
## License
|
210
212
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
@@ -25,6 +25,7 @@ module Tramway::Core::Associations::ClassHelper
|
|
25
25
|
decorate_association association_name
|
26
26
|
end
|
27
27
|
end
|
28
|
+
|
28
29
|
def define_main_association_method(association_name, decorator)
|
29
30
|
define_method association_name do
|
30
31
|
association = object.class.reflect_on_association(association_name)
|
@@ -6,7 +6,7 @@ module Tramway::Core::Associations::ObjectHelper
|
|
6
6
|
object.send(association.name).class
|
7
7
|
else
|
8
8
|
unless association.options[:class_name]
|
9
|
-
error = Tramway::Error.new(plugin: :core, method: :decorate_association, message: "Please, specify `#{
|
9
|
+
error = Tramway::Error.new(plugin: :core, method: :decorate_association, message: "Please, specify `#{association.name}` association class_name in #{object.class} model. For example: `has_many :#{association.name}, class_name: '#{association.name.to_s.singularize.camelize}'`")
|
10
10
|
raise error.message
|
11
11
|
end
|
12
12
|
association.options[:class_name]
|
@@ -1,179 +1,116 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
if association_class.nil?
|
18
|
-
raise Tramway::Error.new(plugin: :core, method: :initialize, message: 'Polymorphic association class is nil. Maybe, you should write `assocation #{association_name}` after `properties #{association_name}_id, #{association_name}_type`')
|
19
|
-
else
|
20
|
-
super association_class.find value.split('_')[-1]
|
21
|
-
send "#{association}_type=", association_class.to_s
|
22
|
-
end
|
23
|
-
end
|
24
|
-
else
|
25
|
-
self.class.send(:define_method, "#{association}=") do |value|
|
26
|
-
super class_name.find value
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
delegating object
|
3
|
+
class Tramway::Core::ApplicationForm < ::Reform::Form
|
4
|
+
include Tramway::Core::ApplicationForms::AssociationObjectHelpers
|
5
|
+
include Tramway::Core::ApplicationForms::ConstantObjectActions
|
6
|
+
include Tramway::Core::ApplicationForms::PropertiesObjectHelper
|
7
|
+
|
8
|
+
def initialize(object = nil)
|
9
|
+
object ||= self.class.model_class.new
|
10
|
+
super(object).tap do
|
11
|
+
@@model_class = object.class
|
12
|
+
@@enumerized_attributes = object.class.try :enumerized_attributes
|
13
|
+
@@associations ||= []
|
14
|
+
|
15
|
+
self.class.full_class_name_associations&.each do |association, class_name|
|
16
|
+
define_association_method association, class_name
|
32
17
|
end
|
33
|
-
end
|
34
18
|
|
35
|
-
|
36
|
-
if params
|
37
|
-
if validate params
|
38
|
-
begin
|
39
|
-
save
|
40
|
-
rescue StandardError => e
|
41
|
-
error = Tramway::Error.new(plugin: :core, method: :submit, message: "Looks like you have method `#{e.name.to_s.gsub('=', '')}` in #{@@model_class}. You should rename it or rename property in #{self.class}")
|
42
|
-
raise error.message
|
43
|
-
end
|
44
|
-
else
|
45
|
-
@@associations.each do |association|
|
46
|
-
if errors.details[association] == [{ error: :blank }]
|
47
|
-
model.send("#{association}=", send(association))
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
else
|
52
|
-
error = Tramway::Error.new(plugin: :core, method: :submit, message: 'ApplicationForm::Params should not be nil')
|
53
|
-
raise error.message
|
54
|
-
end
|
19
|
+
delegating object
|
55
20
|
end
|
21
|
+
end
|
56
22
|
|
57
|
-
|
58
|
-
|
23
|
+
def submit(params)
|
24
|
+
if params
|
25
|
+
validate(params) ? save : collecting_associations_errors
|
26
|
+
else
|
27
|
+
Tramway::Error.raise_error(:tramway, :core, :application_form, :submit, :params_should_not_be_nil)
|
59
28
|
end
|
29
|
+
end
|
60
30
|
|
61
|
-
|
62
|
-
|
63
|
-
|
31
|
+
def model_name
|
32
|
+
@@model_class.model_name
|
33
|
+
end
|
64
34
|
|
65
|
-
|
66
|
-
|
67
|
-
end
|
35
|
+
class << self
|
36
|
+
include Tramway::Core::ApplicationForms::ConstantClassActions
|
68
37
|
|
69
|
-
|
70
|
-
@form_properties_additional = args
|
71
|
-
end
|
38
|
+
delegate :defined_enums, to: :model_class
|
72
39
|
|
73
|
-
def
|
74
|
-
|
40
|
+
def association(property)
|
41
|
+
properties property
|
42
|
+
@@associations = ((defined?(@@associations) && @@associations) || []) + [property]
|
43
|
+
end
|
75
44
|
|
76
|
-
|
77
|
-
|
78
|
-
@form_properties = YAML.load_file(yaml_config_file_path).deep_symbolize_keys
|
79
|
-
@form_properties.deep_merge! @form_properties_additional if @form_properties_additional
|
80
|
-
@form_properties
|
81
|
-
else
|
82
|
-
[]
|
83
|
-
end
|
45
|
+
def associations(*properties)
|
46
|
+
properties.each { |property| association property }
|
84
47
|
end
|
85
48
|
|
86
|
-
def
|
49
|
+
def full_class_name_associations
|
50
|
+
@@associations&.reduce({}) do |hash, association|
|
51
|
+
options = @@model_class.reflect_on_all_associations(:belongs_to).select do |a|
|
52
|
+
a.name == association.to_sym
|
53
|
+
end.first&.options
|
87
54
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
object.send method
|
55
|
+
if options&.dig(:polymorphic)
|
56
|
+
hash.merge! association => @@model_class.send("#{association}_type").values
|
57
|
+
elsif options.present?
|
58
|
+
hash.merge!(association => (options[:class_name] || association.to_s.camelize).constantize)
|
93
59
|
end
|
60
|
+
hash
|
94
61
|
end
|
95
62
|
end
|
96
63
|
|
97
|
-
def
|
98
|
-
|
99
|
-
hash.merge! property.first => model.values[property.first.to_s]
|
100
|
-
end
|
64
|
+
def full_class_name_association(association_name)
|
65
|
+
full_class_name_associations[association_name]
|
101
66
|
end
|
102
67
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
def association(property)
|
107
|
-
properties property
|
108
|
-
@@associations ||= []
|
109
|
-
@@associations << property
|
110
|
-
end
|
68
|
+
def reflect_on_association(*args)
|
69
|
+
@@model_class.reflect_on_association(*args)
|
70
|
+
end
|
111
71
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
end
|
116
|
-
end
|
72
|
+
def enumerized_attributes
|
73
|
+
@@enumerized_attributes
|
74
|
+
end
|
117
75
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
class_name = options[:class_name] || association.to_s.camelize
|
129
|
-
hash.merge!(association => class_name.constantize)
|
130
|
-
end
|
131
|
-
end
|
132
|
-
hash
|
76
|
+
def model_class
|
77
|
+
if defined?(@@model_class) && @@model_class
|
78
|
+
@@model_class
|
79
|
+
else
|
80
|
+
model_class_name ||= name.to_s.sub(/Form$/, '')
|
81
|
+
begin
|
82
|
+
@@model_class = model_class_name.constantize
|
83
|
+
rescue StandardError
|
84
|
+
Tramway::Error.raise_error :tramway, :core, :application_form, :model_class, :there_is_not_model_class,
|
85
|
+
name: name, model_class_name: model_class_name
|
133
86
|
end
|
134
87
|
end
|
88
|
+
end
|
135
89
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
def enumerized_attributes
|
141
|
-
@@enumerized_attributes
|
142
|
-
end
|
143
|
-
|
144
|
-
def reflect_on_association(*args)
|
145
|
-
@@model_class.reflect_on_association(*args)
|
146
|
-
end
|
147
|
-
|
148
|
-
def model_class
|
149
|
-
if defined?(@@model_class) && @@model_class
|
150
|
-
@@model_class
|
151
|
-
else
|
152
|
-
model_class_name ||= name.to_s.sub(/Form$/, '')
|
153
|
-
begin
|
154
|
-
@@model_class = model_class_name.constantize
|
155
|
-
rescue StandardError
|
156
|
-
error = Tramway::Error.new(plugin: :core, method: :model_class, message: "There is not model class name for #{name}. Should be #{model_class_name} or you can use another class to initialize form object or just initialize form with object.")
|
157
|
-
raise error.message
|
158
|
-
end
|
159
|
-
end
|
160
|
-
end
|
90
|
+
def model_class=(name)
|
91
|
+
@@model_class = name
|
92
|
+
end
|
161
93
|
|
162
|
-
|
163
|
-
|
94
|
+
def validates(attribute, **options)
|
95
|
+
if !defined?(@@model_class) || @@model_class.nil?
|
96
|
+
Tramway::Error.raise_error(:tramway, :core, :application_form, :validates, :you_need_to_set_model_class)
|
164
97
|
end
|
98
|
+
@@model_class.validates attribute, **options
|
99
|
+
end
|
100
|
+
end
|
165
101
|
|
166
|
-
|
167
|
-
ActiveModel
|
168
|
-
end
|
102
|
+
private
|
169
103
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
raise error.message
|
174
|
-
end
|
175
|
-
@@model_class.validates attribute, **options
|
176
|
-
end
|
104
|
+
def collecting_associations_errors
|
105
|
+
@@associations.each do |association|
|
106
|
+
model.send("#{association}=", send(association)) if errors.details[association] == [{ error: :blank }]
|
177
107
|
end
|
178
108
|
end
|
109
|
+
|
110
|
+
def save
|
111
|
+
super
|
112
|
+
rescue StandardError => e
|
113
|
+
Tramway::Error.raise_error :tramway, :core, :application_form, :submit, :looks_like_you_have_method,
|
114
|
+
method_name: e.name.to_s.gsub('=', ''), model_class: @@model_class, class_name: self.class
|
115
|
+
end
|
179
116
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tramway::Core::ApplicationForms::AssociationObjectHelpers
|
4
|
+
def associations
|
5
|
+
@@associations
|
6
|
+
end
|
7
|
+
|
8
|
+
def define_association_method(association, class_name)
|
9
|
+
if class_name.is_a? Array
|
10
|
+
define_polymorphic_association association, class_name
|
11
|
+
else
|
12
|
+
self.class.send(:define_method, "#{association}=") do |value|
|
13
|
+
super class_name.find value
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def define_polymorphic_association(association, _class_name)
|
19
|
+
self.class.send(:define_method, "#{association}=") do |value|
|
20
|
+
association_class = value.split('_')[0..-2].join('_').camelize
|
21
|
+
association_class = association_class.constantize if association_class.is_a? String
|
22
|
+
if association_class.nil?
|
23
|
+
Tramway::Error.raise_error :tramway, :core, :application_form, :initialize, :polymorphic_class_is_nil,
|
24
|
+
association_name: association
|
25
|
+
else
|
26
|
+
super association_class.find value.split('_')[-1]
|
27
|
+
send "#{association}_type=", association_class.to_s
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tramway::Core::ApplicationForms::ConstantObjectActions
|
4
|
+
def delegating(object)
|
5
|
+
%i[to_key errors].each { |method| self.class.send(:define_method, method) { object.send method } }
|
6
|
+
end
|
7
|
+
|
8
|
+
def build_errors; end
|
9
|
+
|
10
|
+
def attributes
|
11
|
+
properties.reduce({}) { |hash, property| hash.merge! property.first => model.values[property.first.to_s] }
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tramway::Core::ApplicationForms::PropertiesObjectHelper
|
4
|
+
def form_properties(**args)
|
5
|
+
@form_properties = args
|
6
|
+
end
|
7
|
+
|
8
|
+
def form_properties_additional(**args)
|
9
|
+
@form_properties_additional = args
|
10
|
+
end
|
11
|
+
|
12
|
+
def properties
|
13
|
+
return @form_properties if @form_properties
|
14
|
+
|
15
|
+
yaml_config_file_path = Rails.root.join('app', 'forms', "#{self.class.name.underscore}.yml")
|
16
|
+
|
17
|
+
return [] unless File.exist? yaml_config_file_path
|
18
|
+
|
19
|
+
@form_properties = YAML.load_file(yaml_config_file_path).deep_symbolize_keys
|
20
|
+
@form_properties.deep_merge! @form_properties_additional if @form_properties_additional
|
21
|
+
@form_properties
|
22
|
+
end
|
23
|
+
end
|
@@ -2,80 +2,13 @@
|
|
2
2
|
|
3
3
|
class Tramway::Core::ExtendableForm
|
4
4
|
class << self
|
5
|
+
include Tramway::Core::ExtendableFormsHelpers::ClassBuilder
|
6
|
+
|
5
7
|
def new(name, simple_properties: {}, **more_properties)
|
6
8
|
if Object.const_defined? name
|
7
9
|
name.constantize
|
8
10
|
else
|
9
|
-
|
10
|
-
properties(*simple_properties.keys) if simple_properties.keys.any?
|
11
|
-
|
12
|
-
define_method 'submit' do |params|
|
13
|
-
model.values ||= {}
|
14
|
-
extended_params = params.except(*simple_properties.keys).except(*jsonb_ignored_properties(more_properties))
|
15
|
-
params.each do |key, value|
|
16
|
-
method_name = "#{key}="
|
17
|
-
send method_name, value if respond_to?(method_name)
|
18
|
-
end
|
19
|
-
model.values = extended_params.permit!.to_h.reduce(model.values) do |hash, pair|
|
20
|
-
hash.merge! pair[0] => pair[1]
|
21
|
-
end
|
22
|
-
super(params) && model.errors.empty?
|
23
|
-
end
|
24
|
-
|
25
|
-
define_method 'properties' do
|
26
|
-
hash = simple_properties.each_with_object({}) do |property, h|
|
27
|
-
h.merge! property[0] => property[1] unless model.class.state_machines.keys.include?(property[0])
|
28
|
-
end
|
29
|
-
more_properties.reduce(hash) do |h, property|
|
30
|
-
h.merge! property[0] => {
|
31
|
-
extended_form_property: property[1][:object]
|
32
|
-
}
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
more_properties.each do |property|
|
37
|
-
define_method property[0] do
|
38
|
-
model.values[property[0]] if model.values
|
39
|
-
end
|
40
|
-
|
41
|
-
case property[1][:object].field_type
|
42
|
-
when 'file'
|
43
|
-
field = property[1][:object]
|
44
|
-
define_method "#{property[0]}=" do |value|
|
45
|
-
file_instance = property[1][:association_model].find_or_create_by "#{model.class.name.underscore}_id" => model.id, "#{field.class.name.underscore}_id" => field.id
|
46
|
-
file_instance.file = value
|
47
|
-
file_instance.save!
|
48
|
-
end
|
49
|
-
else
|
50
|
-
next unless property[1][:validates].present?
|
51
|
-
|
52
|
-
define_method "#{property[0]}=" do |value|
|
53
|
-
property[1][:validates].each do |pair|
|
54
|
-
case pair[0].to_s
|
55
|
-
when 'presence'
|
56
|
-
validator_object = "#{pair[0].to_s.camelize}Validator".constantize.new(attributes: :not_blank)
|
57
|
-
if pair[1] == 'true' && !validator_object.send(:valid?, value)
|
58
|
-
model.errors.add property[0],
|
59
|
-
I18n.t("activerecord.errors.models.#{model.class.name.underscore}.attributes.default.#{pair[0]}", value: value)
|
60
|
-
end
|
61
|
-
when 'inclusion'
|
62
|
-
in_array = pair[1][:in]
|
63
|
-
unless value.in? in_array
|
64
|
-
model.errors.add property[0],
|
65
|
-
I18n.t("activerecord.errors.models.#{model.class.name.underscore}.attributes.default.#{pair[0]}", value: value)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
define_method :jsonb_ignored_properties do |properties|
|
74
|
-
properties.map do |property|
|
75
|
-
property[0].to_s if property[1][:object].field_type == 'file'
|
76
|
-
end.compact
|
77
|
-
end
|
78
|
-
end)
|
11
|
+
build_form_class name, simple_properties, more_properties
|
79
12
|
end
|
80
13
|
end
|
81
14
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tramway::Core::ExtendableFormsHelpers::ClassBuilder
|
4
|
+
def build_form_class(name, simple_properties, more_properties)
|
5
|
+
Object.const_set(name, Class.new(::Tramway::Core::ApplicationForm) do
|
6
|
+
properties(*simple_properties.keys) if simple_properties.keys.any?
|
7
|
+
|
8
|
+
include Tramway::Core::ExtendableFormsHelpers::Submit::ObjectHelpers
|
9
|
+
include Tramway::Core::ExtendableFormsHelpers::Validators
|
10
|
+
extend Tramway::Core::ExtendableFormsHelpers::Submit::ClassHelpers
|
11
|
+
extend Tramway::Core::ExtendableFormsHelpers::PropertiesHelper
|
12
|
+
extend Tramway::Core::ExtendableFormsHelpers::MorePropertiesHelper
|
13
|
+
extend Tramway::Core::ExtendableFormsHelpers::IgnoredPropertiesHelper
|
14
|
+
|
15
|
+
define_submit_method simple_properties, more_properties
|
16
|
+
define_properties_method simple_properties, more_properties
|
17
|
+
define_ignored_properties_method
|
18
|
+
|
19
|
+
more_properties.each do |property|
|
20
|
+
define_property_method property[0]
|
21
|
+
|
22
|
+
case property[1][:object].field_type
|
23
|
+
when 'file'
|
24
|
+
field = property[1][:object]
|
25
|
+
define_file_property_assignment_method property field
|
26
|
+
else
|
27
|
+
next unless property[1][:validates].present?
|
28
|
+
|
29
|
+
define_assignment_method property
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end)
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tramway::Core::ExtendableFormsHelpers::IgnoredPropertiesHelper
|
4
|
+
def define_ignored_properties_method
|
5
|
+
define_method :jsonb_ignored_properties do |properties|
|
6
|
+
properties.map do |property|
|
7
|
+
property[0].to_s if property[1][:object].field_type == 'file'
|
8
|
+
end.compact
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tramway::Core::ExtendableFormsHelpers::MorePropertiesHelper
|
4
|
+
def define_property_method(property_name)
|
5
|
+
define_method property_name do
|
6
|
+
model.values[property_name] if model.values
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def define_assignment_method(property)
|
11
|
+
define_method "#{property[0]}=" do |value|
|
12
|
+
property[1][:validates].each do |pair|
|
13
|
+
make_validates property[0], pair, value
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def define_file_property_assignment_method(property, field)
|
19
|
+
define_method "#{property[0]}=" do |value|
|
20
|
+
file_instance = property[1][:association_model].find_or_create_by(
|
21
|
+
"#{model.class.name.underscore}_id" => model.id, "#{field.class.name.underscore}_id" => field.id
|
22
|
+
)
|
23
|
+
file_instance.file = value
|
24
|
+
file_instance.save!
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tramway::Core::ExtendableFormsHelpers::PropertiesHelper
|
4
|
+
def define_properties_method(simple_properties, more_properties)
|
5
|
+
define_method 'properties' do
|
6
|
+
hash = simple_properties.each_with_object({}) do |property, h|
|
7
|
+
h.merge! property[0] => property[1] unless model.class.state_machines.keys.include?(property[0])
|
8
|
+
end
|
9
|
+
more_properties.reduce(hash) do |h, property|
|
10
|
+
h.merge! property[0] => {
|
11
|
+
extended_form_property: property[1][:object]
|
12
|
+
}
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tramway::Core::ExtendableFormsHelpers::Submit::ClassHelpers
|
4
|
+
def define_submit_method(simple_properties, more_properties)
|
5
|
+
define_method 'submit' do |params|
|
6
|
+
model.values ||= {}
|
7
|
+
extended_params = extended(simple_properties, more_properties, params)
|
8
|
+
params.each do |key, value|
|
9
|
+
method_name = "#{key}="
|
10
|
+
send method_name, value if respond_to?(method_name)
|
11
|
+
end
|
12
|
+
model.values = extended_params.reduce(model.values) do |hash, pair|
|
13
|
+
hash.merge! pair[0] => pair[1]
|
14
|
+
end
|
15
|
+
super(params) && model.errors.empty?
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tramway::Core::ExtendableFormsHelpers::Submit::ObjectHelpers
|
4
|
+
def extended(simple_properties, more_properties, params)
|
5
|
+
params.except(*simple_properties.keys).except(*jsonb_ignored_properties(more_properties)).permit!.to_h
|
6
|
+
end
|
7
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tramway::Core::ExtendableFormsHelpers::Validators
|
4
|
+
def make_validates(property_name, validation, value)
|
5
|
+
case validation[0].to_s
|
6
|
+
when 'presence'
|
7
|
+
presence_validator property_name, validation, value
|
8
|
+
when 'inclusion'
|
9
|
+
inclusion_validator property_name, validation, value
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def presence_validator(property_name, validation, value)
|
14
|
+
validator_object = PresenceValidator.new(attributes: :not_blank)
|
15
|
+
return if validation[1] == 'false'
|
16
|
+
return if validation[1] == 'true' && validator_object.send(:valid?, value)
|
17
|
+
|
18
|
+
model.errors.add(
|
19
|
+
property_name,
|
20
|
+
I18n.t(
|
21
|
+
"activerecord.errors.models.#{model.class.name.underscore}.attributes.default.#{validation[0]}",
|
22
|
+
value: value
|
23
|
+
)
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
def inclusion_validator(property_name, validation, value)
|
28
|
+
in_array = validation[1][:in]
|
29
|
+
|
30
|
+
return if value.in? in_array
|
31
|
+
|
32
|
+
model.errors.add(
|
33
|
+
property_name,
|
34
|
+
I18n.t(
|
35
|
+
"activerecord.errors.models.#{model.class.name.underscore}.attributes.default.#{validation[0]}",
|
36
|
+
value: value
|
37
|
+
)
|
38
|
+
)
|
39
|
+
end
|
40
|
+
end
|
@@ -1,15 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module Tramway
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
style: 'margin-left: 15px' do
|
10
|
-
fa_icon 'copy'
|
11
|
-
end
|
12
|
-
end
|
3
|
+
module Tramway::Core::CopyToClipboardHelper
|
4
|
+
def copy_to_clipboard(id)
|
5
|
+
button_tag class: 'btn btn-info clipboard-btn',
|
6
|
+
data: { clipboard_action: 'copy', clipboard_target: "##{id}" },
|
7
|
+
style: 'margin-left: 15px' do
|
8
|
+
fa_icon 'copy'
|
13
9
|
end
|
14
10
|
end
|
15
11
|
end
|
@@ -1,29 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module Tramway
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
raise error.message
|
13
|
-
end
|
14
|
-
end
|
3
|
+
module Tramway::Core::TitleHelper
|
4
|
+
def title(page_title = default_title)
|
5
|
+
if @application.present?
|
6
|
+
title_text = "#{page_title} | #{@application.try(:title) || @application.public_name}"
|
7
|
+
content_for(:title) { title_text }
|
8
|
+
else
|
9
|
+
Tramway::Error.raise_error(:tramway, :core, :title_helper, :title, :you_should_set_tramway_core_application)
|
10
|
+
end
|
11
|
+
end
|
15
12
|
|
16
|
-
|
17
|
-
|
18
|
-
|
13
|
+
def default_title
|
14
|
+
t('.title')
|
15
|
+
end
|
19
16
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
end
|
26
|
-
end
|
17
|
+
def page_title(action, model_name)
|
18
|
+
if I18n.locale == :ru
|
19
|
+
t("helpers.actions.#{action}") + ' ' + genitive(model_name)
|
20
|
+
else
|
21
|
+
t("helpers.actions.#{action}") + ' ' + model_name.model_name.human.downcase
|
27
22
|
end
|
28
23
|
end
|
29
24
|
end
|
@@ -2,52 +2,50 @@
|
|
2
2
|
|
3
3
|
require 'carrierwave/orm/activerecord' if defined?(CarrierWave::Mount)
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
audited
|
10
|
-
extend ::Enumerize
|
11
|
-
|
12
|
-
state_machine :state, initial: :active do
|
13
|
-
state :active
|
14
|
-
state :removed
|
15
|
-
|
16
|
-
event :remove do
|
17
|
-
transition active: :remove
|
18
|
-
end
|
19
|
-
end
|
5
|
+
class Tramway::Core::ApplicationRecord < ActiveRecord::Base
|
6
|
+
self.abstract_class = true
|
7
|
+
audited
|
8
|
+
extend ::Enumerize
|
20
9
|
|
21
|
-
|
22
|
-
|
23
|
-
|
10
|
+
state_machine :state, initial: :active do
|
11
|
+
state :active
|
12
|
+
state :removed
|
24
13
|
|
25
|
-
|
14
|
+
event :remove do
|
15
|
+
transition active: :remove
|
16
|
+
end
|
17
|
+
end
|
26
18
|
|
27
|
-
|
28
|
-
|
29
|
-
|
19
|
+
scope :active, -> { where state: :active }
|
20
|
+
scope :created_by_user, lambda { |user_id|
|
21
|
+
joins(:audits).where('audits.action = \'create\' AND audits.user_id = ?', user_id)
|
22
|
+
}
|
23
|
+
scope :admin_scope, ->(_arg) { all }
|
30
24
|
|
31
|
-
|
32
|
-
class << self
|
33
|
-
def human_attribute_name(attribute_name, *_args)
|
34
|
-
excepted_attributes = %w[created_at updated_at state]
|
35
|
-
if attribute_name.to_s.in? excepted_attributes
|
36
|
-
I18n.t "activerecord.attributes.tramway/core/application_record.#{attribute_name}"
|
37
|
-
else
|
38
|
-
super attribute_name
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def search_by(*attributes, **associations)
|
43
|
-
pg_search_scope :full_text_search, against: attributes, associated_against: associations
|
44
|
-
end
|
45
|
-
end
|
25
|
+
include ::PgSearch::Model
|
46
26
|
|
47
|
-
|
48
|
-
|
49
|
-
|
27
|
+
def creator
|
28
|
+
audits.where(action: :create).first.user
|
29
|
+
end
|
30
|
+
|
31
|
+
# FIXME: detect inhertited locales
|
32
|
+
class << self
|
33
|
+
def human_attribute_name(attribute_name, *_args)
|
34
|
+
excepted_attributes = %w[created_at updated_at state]
|
35
|
+
if attribute_name.to_s.in? excepted_attributes
|
36
|
+
I18n.t "activerecord.attributes.tramway/core/application_record.#{attribute_name}"
|
37
|
+
else
|
38
|
+
super attribute_name
|
50
39
|
end
|
51
40
|
end
|
41
|
+
|
42
|
+
def search_by(*attributes, **associations)
|
43
|
+
pg_search_scope :full_text_search, against: attributes, associated_against: associations
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# FIXME: detect inhertited locales
|
48
|
+
def human_state_name
|
49
|
+
I18n.t "activerecord.state_machines.tramway/core/application_record.state.states.#{state}"
|
52
50
|
end
|
53
51
|
end
|
@@ -4,7 +4,8 @@ module ImageDefaults
|
|
4
4
|
include CarrierWave::MiniMagick
|
5
5
|
|
6
6
|
def default_url
|
7
|
-
"/images/fallback/#{model.class.model_name.to_s.underscore}/" <<
|
7
|
+
"/images/fallback/#{model.class.model_name.to_s.underscore}/" <<
|
8
|
+
[mounted_as, version_name].compact.join('_') << '.gif'
|
8
9
|
end
|
9
10
|
|
10
11
|
def extension_white_list
|
@@ -44,14 +44,14 @@ class PhotoUploader < ApplicationUploader
|
|
44
44
|
before :cache, :capture_size
|
45
45
|
|
46
46
|
def capture_size(file)
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
47
|
+
return unless version_name.blank?
|
48
|
+
|
49
|
+
if file.path.nil?
|
50
|
+
img = ::MiniMagick::Image.read(file.file)
|
51
|
+
@width = img[:width]
|
52
|
+
@height = img[:height]
|
53
|
+
else
|
54
|
+
@width, @height = `identify -format "%wx %h" #{file.path}`.split(/x/).map(&:to_i)
|
55
55
|
end
|
56
56
|
end
|
57
57
|
end
|
@@ -6,7 +6,7 @@
|
|
6
6
|
plural: {
|
7
7
|
keys: %i[zero one few many],
|
8
8
|
rule: lambda do |n|
|
9
|
-
if n
|
9
|
+
if n.zero?
|
10
10
|
:zero
|
11
11
|
elsif n % 10 == 1 && n % 100 != 11
|
12
12
|
# 1, 21, 31, 41, 51, 61...
|
@@ -14,7 +14,7 @@
|
|
14
14
|
elsif [2, 3, 4].include?(n % 10) && ![12, 13, 14].include?(n % 100)
|
15
15
|
# 2-4, 22-24, 32-34...
|
16
16
|
:few
|
17
|
-
elsif n % 10
|
17
|
+
elsif n % 10.zero? || ![5, 6, 7, 8, 9].include?(n % 10) || ![11, 12, 13, 14].include?(n % 100)
|
18
18
|
# 0, 5-20, 25-30, 35-40...
|
19
19
|
:many
|
20
20
|
end
|
data/lib/tramway/collection.rb
CHANGED
@@ -1,11 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
class
|
5
|
-
|
6
|
-
|
7
|
-
raise 'Please add collection to list method'
|
8
|
-
end
|
3
|
+
class Tramway::Collection
|
4
|
+
class << self
|
5
|
+
def list
|
6
|
+
raise 'Please add collection to list method'
|
9
7
|
end
|
10
8
|
end
|
11
9
|
end
|
@@ -1,20 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
module Collections
|
5
|
-
module Helper
|
6
|
-
def collection_list_by(name:)
|
7
|
-
begin
|
8
|
-
require name # needed to load class name with collection
|
9
|
-
rescue LoadError
|
10
|
-
raise "No such file #{name}. You should create file in the `lib/#{name}.rb` or elsewhere you want"
|
11
|
-
end
|
12
|
-
unless ::Tramway::Collection.descendants.map(&:to_s).include?(name.camelize)
|
13
|
-
raise "There no such collection named #{name.camelize}. Please create class with self method `list` and extended of `Tramway::Collection`. You should reload your server after creating this collection."
|
14
|
-
end
|
3
|
+
require 'tramway/collections'
|
15
4
|
|
16
|
-
|
17
|
-
|
5
|
+
module Tramway::Collections::Helper
|
6
|
+
def collection_list_by(name:)
|
7
|
+
begin
|
8
|
+
require name # needed to load class name with collection
|
9
|
+
rescue LoadError
|
10
|
+
raise "No such file #{name}. You should create file in the `lib/#{name}.rb` or elsewhere you want"
|
18
11
|
end
|
12
|
+
unless ::Tramway::Collection.descendants.map(&:to_s).include?(name.camelize)
|
13
|
+
::Tramway::Error.raise_error(
|
14
|
+
:tramway, :collections, :helper, :collection_list_by, :there_no_such_collection,
|
15
|
+
name_camelize: name.camelize
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
name.camelize.constantize.list
|
19
20
|
end
|
20
21
|
end
|
data/lib/tramway/core.rb
CHANGED
@@ -9,37 +9,33 @@ require 'reform'
|
|
9
9
|
require 'pg_search'
|
10
10
|
require 'validators/presence_validator'
|
11
11
|
|
12
|
-
module Tramway
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
@application.send "#{attr}=", value
|
19
|
-
end
|
12
|
+
module Tramway::Core
|
13
|
+
class << self
|
14
|
+
def initialize_application(**options)
|
15
|
+
@application ||= Tramway::Core::Application.new
|
16
|
+
options.each do |attr, value|
|
17
|
+
@application.send "#{attr}=", value
|
20
18
|
end
|
19
|
+
end
|
21
20
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
end
|
29
|
-
else
|
30
|
-
@application
|
21
|
+
def application_object
|
22
|
+
if @application&.model_class.present?
|
23
|
+
begin
|
24
|
+
@application.model_class.first
|
25
|
+
rescue StandardError
|
26
|
+
nil
|
31
27
|
end
|
28
|
+
else
|
29
|
+
@application
|
32
30
|
end
|
33
|
-
|
34
|
-
attr_reader :application
|
35
31
|
end
|
32
|
+
|
33
|
+
attr_reader :application
|
36
34
|
end
|
37
35
|
end
|
38
36
|
|
39
37
|
# HACK: FIXME
|
40
38
|
|
41
|
-
|
42
|
-
|
43
|
-
def merge!(*args); end
|
44
|
-
end
|
39
|
+
class ActiveModel::Errors
|
40
|
+
def merge!(*args); end
|
45
41
|
end
|
data/lib/tramway/core/engine.rb
CHANGED
@@ -5,14 +5,10 @@ require 'tramway/core/application'
|
|
5
5
|
require 'simple_form'
|
6
6
|
require 'enumerize'
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
class Engine < ::Rails::Engine
|
11
|
-
isolate_namespace Tramway::Core
|
8
|
+
class Tramway::Core::Engine < ::Rails::Engine
|
9
|
+
isolate_namespace Tramway::Core
|
12
10
|
|
13
|
-
|
14
|
-
|
15
|
-
end
|
16
|
-
end
|
11
|
+
config.before_initialize do
|
12
|
+
config.i18n.load_path += Dir["#{config.root}/config/locales/**/*.yml"]
|
17
13
|
end
|
18
14
|
end
|
@@ -1,27 +1,27 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'rails/generators'
|
4
|
+
require 'tramway/core/generators'
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
module Generators
|
8
|
-
class InstallGenerator < ::Rails::Generators::Base
|
9
|
-
source_root File.expand_path('templates', __dir__)
|
6
|
+
class Tramway::Core::Generators::InstallGenerator < ::Rails::Generators::Base
|
7
|
+
source_root File.expand_path('templates', __dir__)
|
10
8
|
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
def run_other_generators
|
10
|
+
generate 'audited:install'
|
11
|
+
end
|
14
12
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
13
|
+
def self.next_migration_number(path)
|
14
|
+
next_migration_number = current_migration_number(path) + 1
|
15
|
+
ActiveRecord::Migration.next_migration_number next_migration_number
|
16
|
+
end
|
19
17
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
18
|
+
def copy_initializer
|
19
|
+
simple_form_files = %w[simple_form simple_form_bootstrap]
|
20
|
+
simple_form_files.each do |file|
|
21
|
+
copy_file(
|
22
|
+
"/#{File.dirname __dir__}/generators/templates/initializers/#{file}.rb",
|
23
|
+
"config/initializers/#{file}.rb"
|
24
|
+
)
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
data/lib/tramway/core/version.rb
CHANGED
data/lib/tramway/error.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
class Tramway::Error < RuntimeError
|
4
4
|
def initialize(*args, plugin: nil, method: nil, message: nil)
|
5
|
-
@properties
|
5
|
+
@properties = {}
|
6
6
|
@properties[:plugin] = plugin
|
7
7
|
@properties[:method] = method
|
8
8
|
@properties[:message] = message
|
@@ -16,4 +16,15 @@ class Tramway::Error < RuntimeError
|
|
16
16
|
def properties
|
17
17
|
@properties ||= {}
|
18
18
|
end
|
19
|
+
|
20
|
+
class << self
|
21
|
+
def raise_error(*coordinates, **options)
|
22
|
+
@errors ||= YAML.load_file('..', '..', 'yaml', 'errors.yml').with_indifferent_access
|
23
|
+
error = @errors.dig(*coordinates)
|
24
|
+
options.each do |pair|
|
25
|
+
error.gsub!("%{#{pair[0]}}", pair[1])
|
26
|
+
end
|
27
|
+
raise error
|
28
|
+
end
|
29
|
+
end
|
19
30
|
end
|
metadata
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tramway-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.17.2.
|
4
|
+
version: 1.17.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pavel Kalashnikov
|
8
|
+
- moshiaan
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date: 2020-03-
|
12
|
+
date: 2020-03-19 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: audited
|
@@ -360,7 +361,18 @@ files:
|
|
360
361
|
- app/decorators/tramway/core/concerns/attributes_decorator_helper.rb
|
361
362
|
- app/decorators/tramway/core/delegating/class_helper.rb
|
362
363
|
- app/forms/tramway/core/application_form.rb
|
364
|
+
- app/forms/tramway/core/application_forms/association_object_helpers.rb
|
365
|
+
- app/forms/tramway/core/application_forms/constant_class_actions.rb
|
366
|
+
- app/forms/tramway/core/application_forms/constant_object_actions.rb
|
367
|
+
- app/forms/tramway/core/application_forms/properties_object_helper.rb
|
363
368
|
- app/forms/tramway/core/extendable_form.rb
|
369
|
+
- app/forms/tramway/core/extendable_forms_helpers/class_builder.rb
|
370
|
+
- app/forms/tramway/core/extendable_forms_helpers/ignored_properties_helper.rb
|
371
|
+
- app/forms/tramway/core/extendable_forms_helpers/more_properties_helper.rb
|
372
|
+
- app/forms/tramway/core/extendable_forms_helpers/properties_helper.rb
|
373
|
+
- app/forms/tramway/core/extendable_forms_helpers/submit/class_helpers.rb
|
374
|
+
- app/forms/tramway/core/extendable_forms_helpers/submit/object_helpers.rb
|
375
|
+
- app/forms/tramway/core/extendable_forms_helpers/validators.rb
|
364
376
|
- app/forms/tramway/core/extended_application_form.rb
|
365
377
|
- app/forms/tramway/core/form_creator.rb
|
366
378
|
- app/helpers/tramway/core/copy_to_clipboard_helper.rb
|
@@ -397,10 +409,12 @@ files:
|
|
397
409
|
- lib/string.rb
|
398
410
|
- lib/tasks/tramway/core_tasks.rake
|
399
411
|
- lib/tramway/collection.rb
|
412
|
+
- lib/tramway/collections.rb
|
400
413
|
- lib/tramway/collections/helper.rb
|
401
414
|
- lib/tramway/core.rb
|
402
415
|
- lib/tramway/core/application.rb
|
403
416
|
- lib/tramway/core/engine.rb
|
417
|
+
- lib/tramway/core/generators.rb
|
404
418
|
- lib/tramway/core/generators/install_generator.rb
|
405
419
|
- lib/tramway/core/generators/templates/initializers/simple_form.rb
|
406
420
|
- lib/tramway/core/generators/templates/initializers/simple_form_bootstrap.rb
|
@@ -408,7 +422,7 @@ files:
|
|
408
422
|
- lib/tramway/error.rb
|
409
423
|
- lib/tramway/helpers/class_name_helpers.rb
|
410
424
|
- lib/validators/presence_validator.rb
|
411
|
-
homepage: https://github.com/
|
425
|
+
homepage: https://github.com/purple-magic/tramway-core
|
412
426
|
licenses:
|
413
427
|
- MIT
|
414
428
|
metadata: {}
|