Merge pull request #7521 from betagouv/work_on_logic
feat: amélioration sur le module de logic
This commit is contained in:
commit
222cb1e557
16 changed files with 96 additions and 43 deletions
|
@ -27,8 +27,6 @@ module Logic
|
|||
in [:number, EmptyOperator]
|
||||
operator_class = Eq
|
||||
in [:number, _]
|
||||
in [:string, _]
|
||||
operator_class = Eq
|
||||
end
|
||||
|
||||
if !compatible_type?(left, right)
|
||||
|
@ -41,8 +39,6 @@ module Logic
|
|||
Constant.new(left.options.first)
|
||||
when :number
|
||||
Constant.new(0)
|
||||
when :string
|
||||
Constant.new('')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -60,6 +56,18 @@ module Logic
|
|||
end
|
||||
end
|
||||
|
||||
def self.add_empty_condition_to(condition)
|
||||
empty_condition = EmptyOperator.new(Empty.new, Empty.new)
|
||||
|
||||
if condition.nil?
|
||||
empty_condition
|
||||
elsif [And, Or].include?(condition.class)
|
||||
condition.tap { |c| c.operands << empty_condition }
|
||||
else
|
||||
Logic::And.new([condition, empty_condition])
|
||||
end
|
||||
end
|
||||
|
||||
def ds_eq(left, right) = Logic::Eq.new(left, right)
|
||||
|
||||
def greater_than(left, right) = Logic::GreaterThan.new(left, right)
|
||||
|
|
|
@ -1,4 +1,20 @@
|
|||
class Logic::ChampValue < Logic::Term
|
||||
MANAGED_TYPE_DE_CHAMP = TypeDeChamp.type_champs.slice(
|
||||
:yes_no,
|
||||
:checkbox,
|
||||
:integer_number,
|
||||
:decimal_number,
|
||||
:drop_down_list
|
||||
)
|
||||
|
||||
CHAMP_VALUE_TYPE = {
|
||||
boolean: :boolean,
|
||||
number: :number,
|
||||
enum: :enum,
|
||||
empty: :empty,
|
||||
unmanaged: :unmanaged
|
||||
}
|
||||
|
||||
attr_reader :stable_id
|
||||
|
||||
def initialize(stable_id)
|
||||
|
@ -7,12 +23,12 @@ class Logic::ChampValue < Logic::Term
|
|||
|
||||
def compute(champs)
|
||||
case type_de_champ.type_champ
|
||||
when all_types.fetch(:yes_no),
|
||||
all_types.fetch(:checkbox)
|
||||
when MANAGED_TYPE_DE_CHAMP.fetch(:yes_no),
|
||||
MANAGED_TYPE_DE_CHAMP.fetch(:checkbox)
|
||||
champ(champs).true?
|
||||
when all_types.fetch(:integer_number), all_types.fetch(:decimal_number)
|
||||
when MANAGED_TYPE_DE_CHAMP.fetch(:integer_number), MANAGED_TYPE_DE_CHAMP.fetch(:decimal_number)
|
||||
champ(champs).for_api
|
||||
when all_types.fetch(:drop_down_list), all_types.fetch(:text)
|
||||
when MANAGED_TYPE_DE_CHAMP.fetch(:drop_down_list)
|
||||
champ(champs).value
|
||||
end
|
||||
end
|
||||
|
@ -21,15 +37,15 @@ class Logic::ChampValue < Logic::Term
|
|||
|
||||
def type
|
||||
case type_de_champ.type_champ
|
||||
when all_types.fetch(:yes_no),
|
||||
all_types.fetch(:checkbox)
|
||||
:boolean
|
||||
when all_types.fetch(:integer_number), all_types.fetch(:decimal_number)
|
||||
:number
|
||||
when all_types.fetch(:text)
|
||||
:string
|
||||
when all_types.fetch(:drop_down_list)
|
||||
:enum
|
||||
when MANAGED_TYPE_DE_CHAMP.fetch(:yes_no),
|
||||
MANAGED_TYPE_DE_CHAMP.fetch(:checkbox)
|
||||
CHAMP_VALUE_TYPE.fetch(:boolean)
|
||||
when MANAGED_TYPE_DE_CHAMP.fetch(:integer_number), MANAGED_TYPE_DE_CHAMP.fetch(:decimal_number)
|
||||
CHAMP_VALUE_TYPE.fetch(:number)
|
||||
when MANAGED_TYPE_DE_CHAMP.fetch(:drop_down_list)
|
||||
CHAMP_VALUE_TYPE.fetch(:enum)
|
||||
else
|
||||
CHAMP_VALUE_TYPE.fetch(:unmanaged)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -69,8 +85,4 @@ class Logic::ChampValue < Logic::Term
|
|||
def champ(champs)
|
||||
champs.find { |c| c.stable_id == stable_id }
|
||||
end
|
||||
|
||||
def all_types
|
||||
TypeDeChamp.type_champs
|
||||
end
|
||||
end
|
||||
|
|
|
@ -7,7 +7,16 @@ class Logic::Constant < Logic::Term
|
|||
|
||||
def compute(_champs = nil) = @value
|
||||
|
||||
def to_s = @value.to_s
|
||||
def to_s
|
||||
case @value
|
||||
when TrueClass
|
||||
I18n.t('utils.yes')
|
||||
when FalseClass
|
||||
I18n.t('utils.no')
|
||||
else
|
||||
@value.to_s
|
||||
end
|
||||
end
|
||||
|
||||
def type
|
||||
case @value
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
class Logic::Empty < Logic::Term
|
||||
def to_s = "empty member"
|
||||
def to_s = I18n.t('logic.empty')
|
||||
|
||||
def type = :empty
|
||||
|
||||
|
@ -18,4 +18,8 @@ class Logic::Empty < Logic::Term
|
|||
def ==(other)
|
||||
self.class == other.class
|
||||
end
|
||||
|
||||
def value
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,5 +3,9 @@ class Logic::EmptyOperator < Logic::BinaryOperator
|
|||
|
||||
def type = :empty
|
||||
|
||||
def errors(_stable_ids = nil) = ['empty']
|
||||
def errors(_stable_ids = nil) = []
|
||||
|
||||
def compute(_champs = [])
|
||||
true
|
||||
end
|
||||
end
|
||||
|
|
3
config/locales/models/logic/en.yml
Normal file
3
config/locales/models/logic/en.yml
Normal file
|
@ -0,0 +1,3 @@
|
|||
en:
|
||||
logic:
|
||||
empty: empty member
|
3
config/locales/models/logic/fr.yml
Normal file
3
config/locales/models/logic/fr.yml
Normal file
|
@ -0,0 +1,3 @@
|
|||
fr:
|
||||
logic:
|
||||
empty: un membre vide
|
|
@ -8,7 +8,7 @@ describe Logic::And do
|
|||
|
||||
describe '#to_s' do
|
||||
it do
|
||||
expect(and_from([true, false, true]).to_s).to eq "(true && false && true)"
|
||||
expect(and_from([true, false, true]).to_s).to eq "(Oui && Non && Oui)"
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ describe Logic::BinaryOperator do
|
|||
end
|
||||
|
||||
describe '#errors' do
|
||||
it { expect(greater_than(constant(1), constant(true)).errors).to eq(['les types sont incompatibles : (1 > true)']) }
|
||||
it { expect(greater_than(constant(1), constant(true)).errors).to eq(['les types sont incompatibles : (1 > Oui)']) }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -20,13 +20,6 @@ describe Logic::ChampValue do
|
|||
end
|
||||
end
|
||||
|
||||
context 'text tdc' do
|
||||
let(:champ) { create(:champ_text, value: 'text') }
|
||||
|
||||
it { expect(champ_value(champ.stable_id).type).to eq(:string) }
|
||||
it { is_expected.to eq('text') }
|
||||
end
|
||||
|
||||
context 'integer tdc' do
|
||||
let(:champ) { create(:champ_integer_number, value: '42') }
|
||||
|
||||
|
|
7
spec/models/logic/empty_operator_spec.rb
Normal file
7
spec/models/logic/empty_operator_spec.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
describe Logic::EmptyOperator do
|
||||
include Logic
|
||||
|
||||
describe '#compute' do
|
||||
it { expect(empty_operator(empty, empty).compute).to be true }
|
||||
end
|
||||
end
|
|
@ -13,4 +13,8 @@ describe Logic::Constant do
|
|||
it { expect(empty).to eq(empty) }
|
||||
it { expect(empty).not_to eq(constant(true)) }
|
||||
end
|
||||
|
||||
describe '#to_s' do
|
||||
it { expect(empty.to_s).to eq('un membre vide') }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -8,7 +8,7 @@ describe Logic::Eq do
|
|||
|
||||
describe '#errors' do
|
||||
it { expect(ds_eq(constant(true), constant(true)).errors).to be_empty }
|
||||
it { expect(ds_eq(constant(true), constant(1)).errors).to eq(["les types sont incompatibles : (true == 1)"]) }
|
||||
it { expect(ds_eq(constant(true), constant(1)).errors).to eq(["les types sont incompatibles : (Oui == 1)"]) }
|
||||
end
|
||||
|
||||
describe '#==' do
|
||||
|
|
|
@ -8,7 +8,7 @@ describe Logic::Or do
|
|||
end
|
||||
|
||||
describe '#to_s' do
|
||||
it { expect(or_from([true, false, true]).to_s).to eq "(true || false || true)" }
|
||||
it { expect(or_from([true, false, true]).to_s).to eq "(Oui || Non || Oui)" }
|
||||
end
|
||||
|
||||
def or_from(boolean_to_constants)
|
|
@ -42,12 +42,6 @@ describe Logic do
|
|||
it { is_expected.to eq(ds_eq(constant(1), constant(0))) }
|
||||
end
|
||||
|
||||
context 'when string empty operator true' do
|
||||
let(:condition) { empty_operator(constant('a'), constant(true)) }
|
||||
|
||||
it { is_expected.to eq(ds_eq(constant('a'), constant(''))) }
|
||||
end
|
||||
|
||||
context 'when dropdown empty operator true' do
|
||||
let(:drop_down) { create(:type_de_champ_drop_down_list) }
|
||||
let(:first_option) { drop_down.drop_down_list_enabled_non_empty_options.first }
|
||||
|
@ -79,4 +73,10 @@ describe Logic do
|
|||
# false && (true || true) = false
|
||||
it { expect(ds_and([constant(false), ds_or([constant(true), constant(true)])]).compute).to be false }
|
||||
end
|
||||
|
||||
describe '.add_empty_condition_to' do
|
||||
it { expect(Logic.add_empty_condition_to(nil)).to eq(empty_operator(empty, empty)) }
|
||||
it { expect(Logic.add_empty_condition_to(constant(true))).to eq(ds_and([constant(true), empty_operator(empty, empty)])) }
|
||||
it { expect(Logic.add_empty_condition_to(ds_or([constant(true)]))).to eq(ds_or([constant(true), empty_operator(empty, empty)])) }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -631,7 +631,13 @@ describe ProcedureRevision do
|
|||
|
||||
def second_champ = procedure.draft_revision.types_de_champ_public.second
|
||||
|
||||
let(:procedure) { create(:procedure, :with_type_de_champ, types_de_champ_count: 2) }
|
||||
let(:procedure) do
|
||||
create(:procedure).tap do |p|
|
||||
p.draft_revision.add_type_de_champ(type_champ: :integer_number, libelle: 'l1')
|
||||
p.draft_revision.add_type_de_champ(type_champ: :integer_number, libelle: 'l2')
|
||||
end
|
||||
end
|
||||
|
||||
let(:draft_revision) { procedure.draft_revision }
|
||||
let(:condition) { nil }
|
||||
|
||||
|
@ -649,7 +655,7 @@ describe ProcedureRevision do
|
|||
end
|
||||
|
||||
context 'when a champ has a valid condition: needed tdc is up in the forms' do
|
||||
let(:condition) { ds_eq(constant('oui'), champ_value(first_champ.stable_id)) }
|
||||
let(:condition) { ds_eq(champ_value(first_champ.stable_id), constant(1)) }
|
||||
|
||||
it { is_expected.to be_empty }
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue