Refactorize ChronicDurationAttribute concern

This commit is contained in:
Tomasz Maczukin 2018-03-23 00:12:15 +01:00
parent 973e4030b1
commit c2bc153314
No known key found for this signature in database
GPG Key ID: 7E9EB2E4B0F625CD
2 changed files with 33 additions and 42 deletions

View File

@ -2,49 +2,38 @@ module ChronicDurationAttribute
extend ActiveSupport::Concern extend ActiveSupport::Concern
class_methods do class_methods do
def chronic_duration_attr(virtual_attribute, source_attribute)
chronic_duration_attr_reader(virtual_attribute, source_attribute)
chronic_duration_attr_writer(virtual_attribute, source_attribute)
end
def chronic_duration_attr_reader(virtual_attribute, source_attribute) def chronic_duration_attr_reader(virtual_attribute, source_attribute)
define_method(virtual_attribute) do define_method(virtual_attribute) do
value = self.send(source_attribute) # rubocop:disable GitlabSecurity/PublicSend chronic_duration_attributes[virtual_attribute] || output_chronic_duration_attribute(source_attribute)
return '' if value.nil?
ChronicDuration.output(value, format: :short)
end end
end end
def chronic_duration_attr_writer(virtual_attribute, source_attribute) def chronic_duration_attr_writer(virtual_attribute, source_attribute)
virtual_attribute_validator = "#{virtual_attribute}_validator".to_sym chronic_duration_attr_reader(virtual_attribute, source_attribute)
validation_error = "#{virtual_attribute}_error".to_sym
validate virtual_attribute_validator
attr_accessor validation_error
define_method("#{virtual_attribute}=") do |value| define_method("#{virtual_attribute}=") do |value|
chronic_duration_attributes[virtual_attribute] = value.presence || ''
begin begin
self.send("#{validation_error}=", '') # rubocop:disable GitlabSecurity/PublicSend new_value = ChronicDuration.parse(value).to_i if value.present?
assign_attributes(source_attribute => new_value)
new_value = rescue ChronicDuration::DurationParseError
if value.blank? # ignore error as it will be caught by validation
nil
else
ChronicDuration.parse(value).to_i
end
self.send("#{source_attribute}=", new_value) # rubocop:disable GitlabSecurity/PublicSend
rescue ChronicDuration::DurationParseError => ex
self.send("#{validation_error}=", ex.message) # rubocop:disable GitlabSecurity/PublicSend
end end
end end
define_method(virtual_attribute_validator) do validates virtual_attribute, allow_nil: true, duration: true
error = self.send(validation_error) # rubocop:disable GitlabSecurity/PublicSend
self.send('errors').add(source_attribute, error) unless error.blank? # rubocop:disable GitlabSecurity/PublicSend
end
end end
alias_method :chronic_duration_attr, :chronic_duration_attr_writer
end
def chronic_duration_attributes
@chronic_duration_attributes ||= {}
end
def output_chronic_duration_attribute(source_attribute)
value = attributes[source_attribute.to_s]
ChronicDuration.output(value, format: :short) if value
end end
end end

View File

@ -12,10 +12,10 @@ shared_examples 'ChronicDurationAttribute reader' do
end end
context 'when value is set to nil' do context 'when value is set to nil' do
it 'outputs empty string' do it 'outputs nil' do
subject.send("#{source_field}=", nil) subject.send("#{source_field}=", nil)
expect(subject.send(virtual_field)).to be_empty expect(subject.send(virtual_field)).to be_nil
end end
end end
end end
@ -25,15 +25,15 @@ shared_examples 'ChronicDurationAttribute writer' do
expect(subject.class).to be_public_method_defined("#{virtual_field}=") expect(subject.class).to be_public_method_defined("#{virtual_field}=")
end end
it 'parses chronic duration input' do before do
subject.send("#{virtual_field}=", '10m') subject.send("#{virtual_field}=", '10m')
end
it 'parses chronic duration input' do
expect(subject.send(source_field)).to eq(600) expect(subject.send(source_field)).to eq(600)
end end
it 'passes validation' do it 'passes validation' do
subject.send("#{virtual_field}=", '10m')
expect(subject.valid?).to be_truthy expect(subject.valid?).to be_truthy
end end
@ -54,33 +54,34 @@ shared_examples 'ChronicDurationAttribute writer' do
subject.send("#{virtual_field}=", '-10m') subject.send("#{virtual_field}=", '-10m')
expect(subject.valid?).to be_falsey expect(subject.valid?).to be_falsey
expect(subject.errors&.messages).to include(virtual_field => ['is not a correct duration'])
end end
end end
context 'when empty input is used' do context 'when empty input is used' do
it 'writes nil' do before do
subject.send("#{virtual_field}=", '') subject.send("#{virtual_field}=", '')
end
it 'writes nil' do
expect(subject.send(source_field)).to be_nil expect(subject.send(source_field)).to be_nil
end end
it 'passes validation' do it 'passes validation' do
subject.send("#{virtual_field}=", '')
expect(subject.valid?).to be_truthy expect(subject.valid?).to be_truthy
end end
end end
context 'when nil input is used' do context 'when nil input is used' do
it 'writes nil' do before do
subject.send("#{virtual_field}=", nil) subject.send("#{virtual_field}=", nil)
end
it 'writes nil' do
expect(subject.send(source_field)).to be_nil expect(subject.send(source_field)).to be_nil
end end
it 'passes validation' do it 'passes validation' do
subject.send("#{virtual_field}=", nil)
expect(subject.valid?).to be_truthy expect(subject.valid?).to be_truthy
end end
@ -103,6 +104,7 @@ end
describe 'ChronicDurationAttribute - reader' do describe 'ChronicDurationAttribute - reader' do
let(:source_field) {:timeout} let(:source_field) {:timeout}
let(:virtual_field) {:timeout_human_readable} let(:virtual_field) {:timeout_human_readable}
subject {Ci::BuildMetadata.new} subject {Ci::BuildMetadata.new}
it "doesn't contain dynamically created writer method" do it "doesn't contain dynamically created writer method" do