<commit_before>module Payjp
  class PayjpObject
    include Enumerable

    @@permanent_attributes = Set.new([:id])

    # The default :id method is deprecated and isn't useful to us
    undef :id if method_defined?(:id)

    def initialize(id = nil, opts = {})
      # parameter overloading!
      if id.is_a?(Hash)
        @retrieve_params = id.dup
        @retrieve_params.delete(:id)
        id = id[:id]
      else
        @retrieve_params = {}
      end

      @opts = opts
      @values = {}
      # This really belongs in APIResource, but not putting it there allows us
      # to have a unified inspect method
      @unsaved_values = Set.new
      @transient_values = Set.new
      @values[:id] = id if id
    end

    def self.construct_from(values, opts = {})
      new(values[:id]).refresh_from(values, opts)
    end

    def to_s(*_args)
      JSON.pretty_generate(@values)
    end

    def inspect
      id_string = (self.respond_to?(:id) && !id.nil?) ? " id=#{id}" : ""
      "#<#{self.class}:0x#{object_id.to_s(16)}#{id_string}> JSON: " + JSON.pretty_generate(@values)
    end

    def refresh_from(values, opts, partial = false)
      @opts = opts
      @original_values = Marshal.load(Marshal.dump(values)) # deep copy
      removed = partial ? Set.new : Set.new(@values.keys - values.keys)
      added = Set.new(values.keys - @values.keys)
      # Wipe old state before setting new.  This is useful for e.g. updating a
      # customer, where there is no persistent card parameter.  Mark those values
      # which don't persist as transient

      instance_eval do
        remove_accessors(removed)
        add_accessors(added)
      end
      removed.each do |k|
        @values.delete(k)
        @transient_values.add(k)
        @unsaved_values.delete(k)
      end
      values.each do |k, v|
        @values[k] = Util.convert_to_payjp_object(v, @opts)
        @transient_values.delete(k)
        @unsaved_values.delete(k)
      end

      self
    end

    def [](k)
      @values[k.to_sym]
    end

    def []=(k, v)
      send(:"#{k}=", v)
    end

    def keys
      @values.keys
    end

    def values
      @values.values
    end

    def to_json(*_a)
      JSON.generate(@values)
    end

    def as_json(*a)
      @values.as_json(*a)
    end

    def to_hash
      @values.inject({}) do |acc, (key, value)|
        acc[key] = value.respond_to?(:to_hash) ? value.to_hash : value
        acc
      end
    end

    def each(&blk)
      @values.each(&blk)
    end

    def _dump(_level)
      Marshal.dump([@values, @opts])
    end

    def self._load(args)
      values, opts = Marshal.load(args)
      construct_from(values, opts)
    end

    if RUBY_VERSION < '1.9.2'
      def respond_to?(symbol)
        @values.has_key?(symbol) || super
      end
    end

    def serialize_nested_object(key)
      new_value = @values[key]
      return {} if new_value.is_a?(APIResource)

      if @unsaved_values.include?(key)
        # the object has been reassigned
        # e.g. as object.key = {foo => bar}
        update = new_value
        new_keys = update.keys.map(&:to_sym)

        # remove keys at the server, but not known locally
        if @original_values.include?(key)
          keys_to_unset = @original_values[key].keys - new_keys
          keys_to_unset.each { |key| update[key] = '' }<commit_msg>suppress warning; resolve local variable shadowing<commit_after>module Payjp
  class PayjpObject
    include Enumerable

    @@permanent_attributes = Set.new([:id])

    # The default :id method is deprecated and isn't useful to us
    undef :id if method_defined?(:id)

    def initialize(id = nil, opts = {})
      # parameter overloading!
      if id.is_a?(Hash)
        @retrieve_params = id.dup
        @retrieve_params.delete(:id)
        id = id[:id]
      else
        @retrieve_params = {}
      end

      @opts = opts
      @values = {}
      # This really belongs in APIResource, but not putting it there allows us
      # to have a unified inspect method
      @unsaved_values = Set.new
      @transient_values = Set.new
      @values[:id] = id if id
    end

    def self.construct_from(values, opts = {})
      new(values[:id]).refresh_from(values, opts)
    end

    def to_s(*_args)
      JSON.pretty_generate(@values)
    end

    def inspect
      id_string = (self.respond_to?(:id) && !id.nil?) ? " id=#{id}" : ""
      "#<#{self.class}:0x#{object_id.to_s(16)}#{id_string}> JSON: " + JSON.pretty_generate(@values)
    end

    def refresh_from(values, opts, partial = false)
      @opts = opts
      @original_values = Marshal.load(Marshal.dump(values)) # deep copy
      removed = partial ? Set.new : Set.new(@values.keys - values.keys)
      added = Set.new(values.keys - @values.keys)
      # Wipe old state before setting new.  This is useful for e.g. updating a
      # customer, where there is no persistent card parameter.  Mark those values
      # which don't persist as transient

      instance_eval do
        remove_accessors(removed)
        add_accessors(added)
      end
      removed.each do |k|
        @values.delete(k)
        @transient_values.add(k)
        @unsaved_values.delete(k)
      end
      values.each do |k, v|
        @values[k] = Util.convert_to_payjp_object(v, @opts)
        @transient_values.delete(k)
        @unsaved_values.delete(k)
      end

      self
    end

    def [](k)
      @values[k.to_sym]
    end

    def []=(k, v)
      send(:"#{k}=", v)
    end

    def keys
      @values.keys
    end

    def values
      @values.values
    end

    def to_json(*_a)
      JSON.generate(@values)
    end

    def as_json(*a)
      @values.as_json(*a)
    end

    def to_hash
      @values.inject({}) do |acc, (key, value)|
        acc[key] = value.respond_to?(:to_hash) ? value.to_hash : value
        acc
      end
    end

    def each(&blk)
      @values.each(&blk)
    end

    def _dump(_level)
      Marshal.dump([@values, @opts])
    end

    def self._load(args)
      values, opts = Marshal.load(args)
      construct_from(values, opts)
    end

    if RUBY_VERSION < '1.9.2'
      def respond_to?(symbol)
        @values.has_key?(symbol) || super
      end
    end

    def serialize_nested_object(key)
      new_value = @values[key]
      return {} if new_value.is_a?(APIResource)

      if @unsaved_values.include?(key)
        # the object has been reassigned
        # e.g. as object.key = {foo => bar}
        update = new_value
        new_keys = update.keys.map(&:to_sym)

        # remove keys at the server, but not known locally
        if @original_values.include?(key)
          keys_to_unset = @original_values[key].keys - new_keys
          keys_to_unset.each { |unset_key| update[unset_key] = '' }
{'fraction_non_alphanumeric': 0.1167633496950766, 'fraction_numerical': 0.00178491744756805, 'mean_word_length': 2.2483091787439613, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1327952', 'n_tokens_mistral': 2251, 'n_tokens_neox': 2204, 'n_words': 539}