diff --git a/features/abbreviations_cn22.yml b/features/abbreviations_cn22.yml new file mode 100644 index 0000000..b1e108c --- /dev/null +++ b/features/abbreviations_cn22.yml @@ -0,0 +1,3 @@ +--- +user: + id: 1 diff --git a/features/file_s3.yml b/features/file_s3.yml new file mode 100644 index 0000000..b1e108c --- /dev/null +++ b/features/file_s3.yml @@ -0,0 +1,3 @@ +--- +user: + id: 1 diff --git a/features/s3_file.yml b/features/s3_file.yml new file mode 100644 index 0000000..b1e108c --- /dev/null +++ b/features/s3_file.yml @@ -0,0 +1,3 @@ +--- +user: + id: 1 diff --git a/lib/toggles/constant_lookup.rb b/lib/toggles/constant_lookup.rb index 8107577..cafbf85 100644 --- a/lib/toggles/constant_lookup.rb +++ b/lib/toggles/constant_lookup.rb @@ -8,13 +8,13 @@ def initialize(sym) end end - # Return a tree walker that translates Module#const_missing(sym) into the next child node # # So Features::Cat::BearDog walks as: # * next_features = Feature.features # root # * const_missing(:Cat) => next_features = next_features['cat'] # * const_missing(:BearDog) => next_features['bear_dog'] + # * const_missing(:CN22) => next_features['c_n_22'] # # Defined at Toggles.features_dir + "/cat/bear_dog.yaml" # @@ -22,21 +22,24 @@ def initialize(sym) def self.from(features, path) Class.new { class << self - attr_accessor :features - attr_accessor :path + attr_accessor :features, :path def const_missing(sym) - subtree_or_feature = features.fetch( - # translate class name into path part i.e :BearDog #=> 'bear_dog' - sym.to_s.gsub(/([a-z])([A-Z])/) { |s| s.chars.join('_') }.downcase.to_sym, - ) + # translate class name into path part i.e :BearDog #=> 'bear_dog' + key = sym.to_s + key.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2'.freeze) + key.gsub!(/([a-z\d])([A-Z])/, '\1_\2'.freeze) + key.downcase! + + subtree_or_feature = features.fetch(key.to_sym) + if subtree_or_feature.is_a?(Hash) Feature::ConstantLookup.from(subtree_or_feature, path + [sym]) else subtree_or_feature end rescue KeyError - raise Error.new(path + [sym]) + raise Error, path + [sym] end end }.tap do |resolver| diff --git a/lib/toggles/version.rb b/lib/toggles/version.rb index b4a5875..0af0489 100644 --- a/lib/toggles/version.rb +++ b/lib/toggles/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Toggles - VERSION = '0.3.0' + VERSION = '0.3.2' end diff --git a/spec/toggles/feature/base_spec.rb b/spec/toggles/feature/base_spec.rb index 1440401..07f5a74 100644 --- a/spec/toggles/feature/base_spec.rb +++ b/spec/toggles/feature/base_spec.rb @@ -2,9 +2,35 @@ let(:user) { double(id: 1, logged_in?: true) } let(:widget) { double(id: 2) } - subject { Feature::MultipleSubjects.new(user: user, widget: widget) } + context 'multiple subjects' do + subject { Feature::MultipleSubjects.new(user: user, widget: widget) } - its(:enabled?) { is_expected.to eq true } - its(:subjects) { is_expected.to eq user: user, widget: widget } - its("permissions.subjects") { is_expected.to eq [:user, :widget] } + its(:enabled?) do is_expected.to eq true end + its(:subjects) do is_expected.to eq user: user, widget: widget end + its('permissions.subjects') { is_expected.to eq %i[user widget] } + end + + context 'abbreviation with numbers' do + subject { Feature::AbbreviationsCN22.new(user: user) } + + its(:enabled?) do is_expected.to eq true end + its(:subjects) do is_expected.to eq user: user end + its('permissions.subjects') { is_expected.to eq [:user] } + end + + context 'irregular capitalization' do + subject { Feature::S3File.new(user: user) } + + its(:enabled?) do is_expected.to eq true end + its(:subjects) do is_expected.to eq user: user end + its('permissions.subjects') { is_expected.to eq [:user] } + end + + context 'irregular capitalization' do + subject { Feature::FileS3.new(user: user) } + + its(:enabled?) do is_expected.to eq true end + its(:subjects) do is_expected.to eq user: user end + its('permissions.subjects') { is_expected.to eq [:user] } + end end