lib/mongoid/history/options.rb in mongoid-history-0.8.3 vs lib/mongoid/history/options.rb in mongoid-history-0.8.5

- old
+ new

@@ -1,177 +1,177 @@ -module Mongoid - module History - class Options - attr_reader :trackable, :options - - def initialize(trackable, opts = {}) - @trackable = trackable - @options = default_options.merge(opts) - end - - def scope - trackable.collection_name.to_s.singularize.to_sym - end - - def prepared - return @prepared if @prepared - @prepared = options.dup - prepare_skipped_fields - prepare_formatted_fields - parse_tracked_fields_and_relations - @prepared - end - - private - - def default_options - { on: :all, - except: %i[created_at updated_at], - tracker_class_name: nil, - modifier_field: :modifier, - version_field: :version, - changes_method: :changes, - scope: scope, - track_create: true, - track_update: true, - track_destroy: true, - format: nil } - end - - # Sets the :except attributes and relations in `options` to be an [ Array <String> ] - # The attribute names and relations are stored by their `database_field_name`s - # Removes the `nil` and duplicate entries from skipped attributes/relations list - def prepare_skipped_fields - # normalize :except fields to an array of database field strings - @prepared[:except] = Array(@prepared[:except]) - @prepared[:except] = @prepared[:except].map { |field| trackable.database_field_name(field) }.compact.uniq - end - - def prepare_formatted_fields - formats = {} - - if @prepared[:format].class == Hash - @prepared[:format].each do |field, format| - next if field.nil? - - field = trackable.database_field_name(field) - - if format.class == Hash && trackable.embeds_many?(field) - relation_class = trackable.relation_class_of(field) - formats[field] = format.inject({}) { |a, e| a.merge(relation_class.database_field_name(e.first) => e.last) } - elsif format.class == Hash && trackable.embeds_one?(field) - relation_class = trackable.relation_class_of(field) - formats[field] = format.inject({}) { |a, e| a.merge(relation_class.database_field_name(e.first) => e.last) } - else - formats[field] = format - end - end - end - - @prepared[:format] = formats - end - - def parse_tracked_fields_and_relations - # case `options[:on]` - # when `posts: [:id, :title]`, then it will convert it to `[[:posts, [:id, :title]]]` - # when `:foo`, then `[:foo]` - # when `[:foo, { posts: [:id, :title] }]`, then return as is - @prepared[:on] = Array(@prepared[:on]) - - @prepared[:on] = @prepared[:on].map { |opt| opt == :all ? :fields : opt } - - if @prepared[:on].include?(:fields) - @prepared[:on] = @prepared[:on].reject { |opt| opt == :fields } - @prepared[:on] = @prepared[:on] | trackable.fields.keys.map(&:to_sym) - reserved_fields.map(&:to_sym) - end - - if @prepared[:on].include?(:embedded_relations) - @prepared[:on] = @prepared[:on].reject { |opt| opt == :embedded_relations } - @prepared[:on] = @prepared[:on] | trackable.embedded_relations.keys - end - - @prepared[:fields] = [] - @prepared[:dynamic] = [] - @prepared[:relations] = { embeds_one: {}, embeds_many: {} } - - @prepared[:on].each do |option| - if option.is_a?(Hash) - option.each { |k, v| split_and_categorize(k => v) } - else - split_and_categorize(option) - end - end - end - - def split_and_categorize(field_and_options) - field = get_database_field_name(field_and_options) - field_options = get_field_options(field_and_options) - categorize_tracked_option(field, field_options) - end - - # Returns the database_field_name key for tracked option - # - # @param [ String | Symbol | Array | Hash ] option The field or relation name to track - # - # @return [ String ] the database field name for tracked option - def get_database_field_name(option) - key = if option.is_a?(Hash) - option.keys.first - elsif option.is_a?(Array) - option.first - end - trackable.database_field_name(key || option) - end - - # Returns the tracked attributes for embedded relations, otherwise `nil` - # - # @param [ String | Symbol | Array | Hash ] option The field or relation name to track - # - # @return [ nil | Array <String | Symbol> ] the list of tracked fields for embedded relation - def get_field_options(option) - if option.is_a?(Hash) - option.values.first - elsif option.is_a?(Array) - option.last - end - end - - # Tracks the passed option under: - # `fields` - # `dynamic` - # `relations -> embeds_one` or - # `relations -> embeds_many` - # - # @param [ String ] field The database field name of field or relation to track - # @param [ nil | Array <String | Symbol> ] field_options The tracked fields for embedded relations - def categorize_tracked_option(field, field_options = nil) - return if @prepared[:except].include?(field) - return if reserved_fields.include?(field) - - field_options = Array(field_options) - - if trackable.embeds_one?(field) - track_relation(field, :embeds_one, field_options) - elsif trackable.embeds_many?(field) - track_relation(field, :embeds_many, field_options) - elsif trackable.fields.keys.include?(field) - @prepared[:fields] << field - else - @prepared[:dynamic] << field - end - end - - def track_relation(field, kind, field_options) - relation_class = trackable.relation_class_of(field) - @prepared[:relations][kind][field] = if field_options.blank? - relation_class.fields.keys - else - %w[_id] | field_options.map { |opt| relation_class.database_field_name(opt) } - end - end - - def reserved_fields - @reserved_fields ||= ['_id', '_type', @prepared[:version_field].to_s, "#{@prepared[:modifier_field]}_id"] - end - end - end -end +module Mongoid + module History + class Options + attr_reader :trackable, :options + + def initialize(trackable, opts = {}) + @trackable = trackable + @options = default_options.merge(opts) + end + + def scope + trackable.collection_name.to_s.singularize.to_sym + end + + def prepared + return @prepared if @prepared + @prepared = options.dup + prepare_skipped_fields + prepare_formatted_fields + parse_tracked_fields_and_relations + @prepared + end + + private + + def default_options + { on: :all, + except: %i[created_at updated_at], + tracker_class_name: nil, + modifier_field: :modifier, + version_field: :version, + changes_method: :changes, + scope: scope, + track_create: true, + track_update: true, + track_destroy: true, + format: nil } + end + + # Sets the :except attributes and relations in `options` to be an [ Array <String> ] + # The attribute names and relations are stored by their `database_field_name`s + # Removes the `nil` and duplicate entries from skipped attributes/relations list + def prepare_skipped_fields + # normalize :except fields to an array of database field strings + @prepared[:except] = Array(@prepared[:except]) + @prepared[:except] = @prepared[:except].map { |field| trackable.database_field_name(field) }.compact.uniq + end + + def prepare_formatted_fields + formats = {} + + if @prepared[:format].class == Hash + @prepared[:format].each do |field, format| + next if field.nil? + + field = trackable.database_field_name(field) + + if format.class == Hash && trackable.embeds_many?(field) + relation_class = trackable.relation_class_of(field) + formats[field] = format.inject({}) { |a, e| a.merge(relation_class.database_field_name(e.first) => e.last) } + elsif format.class == Hash && trackable.embeds_one?(field) + relation_class = trackable.relation_class_of(field) + formats[field] = format.inject({}) { |a, e| a.merge(relation_class.database_field_name(e.first) => e.last) } + else + formats[field] = format + end + end + end + + @prepared[:format] = formats + end + + def parse_tracked_fields_and_relations + # case `options[:on]` + # when `posts: [:id, :title]`, then it will convert it to `[[:posts, [:id, :title]]]` + # when `:foo`, then `[:foo]` + # when `[:foo, { posts: [:id, :title] }]`, then return as is + @prepared[:on] = Array(@prepared[:on]) + + @prepared[:on] = @prepared[:on].map { |opt| opt == :all ? :fields : opt } + + if @prepared[:on].include?(:fields) + @prepared[:on] = @prepared[:on].reject { |opt| opt == :fields } + @prepared[:on] = @prepared[:on] | trackable.fields.keys.map(&:to_sym) - reserved_fields.map(&:to_sym) + end + + if @prepared[:on].include?(:embedded_relations) + @prepared[:on] = @prepared[:on].reject { |opt| opt == :embedded_relations } + @prepared[:on] = @prepared[:on] | trackable.embedded_relations.keys + end + + @prepared[:fields] = [] + @prepared[:dynamic] = [] + @prepared[:relations] = { embeds_one: {}, embeds_many: {} } + + @prepared[:on].each do |option| + if option.is_a?(Hash) + option.each { |k, v| split_and_categorize(k => v) } + else + split_and_categorize(option) + end + end + end + + def split_and_categorize(field_and_options) + field = get_database_field_name(field_and_options) + field_options = get_field_options(field_and_options) + categorize_tracked_option(field, field_options) + end + + # Returns the database_field_name key for tracked option + # + # @param [ String | Symbol | Array | Hash ] option The field or relation name to track + # + # @return [ String ] the database field name for tracked option + def get_database_field_name(option) + key = if option.is_a?(Hash) + option.keys.first + elsif option.is_a?(Array) + option.first + end + trackable.database_field_name(key || option) + end + + # Returns the tracked attributes for embedded relations, otherwise `nil` + # + # @param [ String | Symbol | Array | Hash ] option The field or relation name to track + # + # @return [ nil | Array <String | Symbol> ] the list of tracked fields for embedded relation + def get_field_options(option) + if option.is_a?(Hash) + option.values.first + elsif option.is_a?(Array) + option.last + end + end + + # Tracks the passed option under: + # `fields` + # `dynamic` + # `relations -> embeds_one` or + # `relations -> embeds_many` + # + # @param [ String ] field The database field name of field or relation to track + # @param [ nil | Array <String | Symbol> ] field_options The tracked fields for embedded relations + def categorize_tracked_option(field, field_options = nil) + return if @prepared[:except].include?(field) + return if reserved_fields.include?(field) + + field_options = Array(field_options) + + if trackable.embeds_one?(field) + track_relation(field, :embeds_one, field_options) + elsif trackable.embeds_many?(field) + track_relation(field, :embeds_many, field_options) + elsif trackable.fields.keys.include?(field) + @prepared[:fields] << field + else + @prepared[:dynamic] << field + end + end + + def track_relation(field, kind, field_options) + relation_class = trackable.relation_class_of(field) + @prepared[:relations][kind][field] = if field_options.blank? + relation_class.fields.keys + else + %w[_id] | field_options.map { |opt| relation_class.database_field_name(opt) } + end + end + + def reserved_fields + @reserved_fields ||= ['_id', '_type', @prepared[:version_field].to_s, "#{@prepared[:modifier_field]}_id"] + end + end + end +end