diff --git a/app/models/blog_archives_block.rb b/app/models/blog_archives_block.rb index c700d3e..30687af 100644 --- a/app/models/blog_archives_block.rb +++ b/app/models/blog_archives_block.rb @@ -15,7 +15,7 @@ class BlogArchivesBlock < Block _('Blog posts') end - settings_items :blog_id, Integer + settings_items :blog_id, type: Integer def blog blog_id && owner.blogs.exists?(blog_id) ? owner.blogs.find(blog_id) : owner.blog diff --git a/app/models/link_list_block.rb b/app/models/link_list_block.rb index 4068a68..e6503b7 100644 --- a/app/models/link_list_block.rb +++ b/app/models/link_list_block.rb @@ -41,7 +41,7 @@ class LinkListBlock < Block [N_('New window'), '_new'], ] - settings_items :links, Array, :default => [] + settings_items :links, type: Array, :default => [] before_save do |block| block.links = block.links.delete_if {|i| i[:name].blank? and i[:address].blank?} diff --git a/app/models/products_block.rb b/app/models/products_block.rb index 7494691..3e1ad06 100644 --- a/app/models/products_block.rb +++ b/app/models/products_block.rb @@ -39,7 +39,7 @@ class ProductsBlock < Block link_to(_('View all products'), owner.public_profile_url.merge(:controller => 'catalog', :action => 'index')) end - settings_items :product_ids, Array + settings_items :product_ids, type: Array def product_ids=(array) self.settings[:product_ids] = array if self.settings[:product_ids] diff --git a/lib/acts_as_having_settings.rb b/lib/acts_as_having_settings.rb index e808b11..e454bcb 100644 --- a/lib/acts_as_having_settings.rb +++ b/lib/acts_as_having_settings.rb @@ -1,64 +1,81 @@ +# declare missing types +module ActiveRecord + module Type + class Symbol < Value + def cast_value value + value.to_sym + end + end + class Array < Value + def cast_value value + Array(value) + end + end + class Hash < Value + def cast_value value + Hash[value] + end + end + end +end + module ActsAsHavingSettings module ClassMethods + def acts_as_having_settings(*args) options = args.last.is_a?(Hash) ? args.pop : {} - - settings_field = options[:field] || 'settings' + field = (options[:field] || :settings).to_sym - class_eval <<-CODE - serialize :#{settings_field}, Hash - def self.settings_field - #{settings_field.inspect} - end - def #{settings_field} - self[:#{settings_field}] ||= Hash.new + serialize field, Hash + class_attribute :settings_field + self.settings_field = field + + class_eval do + def settings_field + self[self.class.settings_field] ||= Hash.new end - def setting_changed?(setting_field) + def setting_changed? setting_field setting_field = setting_field.to_sym - changed_settings = self.changes['#{settings_field}'] + changed_settings = self.changes[self.class.settings_field] return false if changed_settings.nil? old_setting_value = changed_settings.first.nil? ? nil : changed_settings.first[setting_field] new_setting_value = changed_settings.last[setting_field] old_setting_value != new_setting_value end + end - before_save :symbolize_settings_keys - private - def symbolize_settings_keys - self[:#{settings_field}] && self[:#{settings_field}].symbolize_keys! - end - CODE - settings_items(*args) + settings_items *args end def settings_items(*names) options = names.last.is_a?(Hash) ? names.pop : {} - default = (!options[:default].nil?) ? options[:default].inspect : "val" - data_type = options[:type] || :string + default = if !options[:default].nil? then options[:default] else nil end + data_type = options[:type] + data_type = if data_type.present? then data_type.to_s.camelize.to_sym else :String end + data_type = ActiveRecord::Type.const_get(data_type).new names.each do |setting| - class_eval <<-CODE - def #{setting} - val = send(self.class.settings_field)[:#{setting}] - val.nil? ? (#{default}.is_a?(String) ? gettext(#{default}) : #{default}) : val - end - def #{setting}=(value) - h = send(self.class.settings_field).clone - h[:#{setting}] = self.class.acts_as_having_settings_type_cast(value, #{data_type.inspect}) - send(self.class.settings_field.to_s + '=', h) - end - CODE + # symbolize key + setting = setting.to_sym + + define_method setting do + h = send self.class.settings_field + val = h[setting] + if val.nil? then (if default.is_a? String then gettext default else default end) else val end + end + define_method "#{setting}=" do |value| + h = send self.class.settings_field + h[setting] = self.class.acts_as_having_settings_type_cast value, data_type + end end end - def acts_as_having_settings_type_cast(value, type) - # FIXME creating a new instance at every call, will the garbage collector - # be able to cope with it? - ActiveRecord::ConnectionAdapters::Column.new(:dummy, nil, type.to_s).type_cast(value) + def acts_as_having_settings_type_cast value, type + type.send :cast_value, value end end diff --git a/plugins/statistics/lib/statistics_block.rb b/plugins/statistics/lib/statistics_block.rb index 9374341..03682ff 100644 --- a/plugins/statistics/lib/statistics_block.rb +++ b/plugins/statistics/lib/statistics_block.rb @@ -8,7 +8,7 @@ class StatisticsBlock < Block settings_items :tag_counter, :default => true settings_items :comment_counter, :default => true settings_items :hit_counter, :default => false - settings_items :templates_ids_counter, Hash, :default => {} + settings_items :templates_ids_counter, type: Hash, default: {} attr_accessible :comment_counter, :community_counter, :user_counter, :enterprise_counter, :product_counter, :category_counter, :tag_counter, :hit_counter, :templates_ids_counter diff --git a/test/unit/acts_as_having_settings_test.rb b/test/unit/acts_as_having_settings_test.rb index 2afa4fc..4a0f1df 100644 --- a/test/unit/acts_as_having_settings_test.rb +++ b/test/unit/acts_as_having_settings_test.rb @@ -2,11 +2,12 @@ require_relative "../test_helper" class ActsAsHavingSettingsTest < ActiveSupport::TestCase - # using Block class as a sample user of the module + # using Block class as a sample user of the module class TestClass < Block - settings_items :flag, :type => :boolean - settings_items :flag_disabled_by_default, :type => :boolean, :default => false - settings_items :name, :type => :string, :default => N_('ENGLISH TEXT') + settings_items :flag, type: :boolean + settings_items :flag_disabled_by_default, type: :boolean, default: false + # to test that 'name' will be symbolized (see below) + settings_items 'name', type: :string, default: N_('ENGLISH TEXT') attr_accessible :flag, :name, :flag_disabled_by_default end @@ -26,7 +27,7 @@ class ActsAsHavingSettingsTest < ActiveSupport::TestCase assert !block.respond_to?(:limit) assert !block.respond_to?(:limit=) - block_class.settings_items :limit + block_class.settings_items :limit, type: :integer assert_respond_to block, :limit assert_respond_to block, :limit= @@ -35,7 +36,7 @@ class ActsAsHavingSettingsTest < ActiveSupport::TestCase block.limit = 10 assert_equal 10, block.limit - assert_equal({ :limit => 10}, block.settings) + assert_equal({ limit: 10}, block.settings) end should 'properly save the settings' do @@ -50,7 +51,7 @@ class ActsAsHavingSettingsTest < ActiveSupport::TestCase should 'be able to specify default values' do block_class = Class.new(Block) - block_class.settings_items :some_setting, :default => 10 + block_class.settings_items :some_setting, default: 10 assert_equal 10, block_class.new.some_setting end @@ -75,10 +76,9 @@ class ActsAsHavingSettingsTest < ActiveSupport::TestCase assert_equal true, obj.flag end - should 'symbolize keys when save' do + should 'have keys as symbols' do obj = TestClass.new - obj.settings.expects(:symbolize_keys!).once - assert obj.save + assert obj.settings.all?{ |k,v| k.is_a? Symbol } end should 'setting_changed be true if a setting passed as parameter was changed' do @@ -101,14 +101,14 @@ class ActsAsHavingSettingsTest < ActiveSupport::TestCase end should 'setting_changed be false if a setting passed as parameter was not changed but another setting is changed' do - obj = TestClass.new(:name => 'some name') + obj = TestClass.new(name: 'some name') obj.save obj.name = 'antoher nme' assert !obj.setting_changed?('flag') end should 'setting_changed be true for all changed fields' do - obj = TestClass.new(:name => 'some name', :flag => false) + obj = TestClass.new(name: 'some name', flag: false) obj.save obj.name = 'another nme' obj.flag = true -- libgit2 0.21.2