Guest User

Untitled

a guest
Feb 19th, 2018
85
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 2.92 KB | None | 0 0
  1. require 'hash/dirty'
  2.  
  3. # DirtyHash behaves just like Hash, but keeps track of changes applied to it.
  4. #
  5. # @example
  6. # dh = DirtyHash.with :x => 1
  7. # dh.clean? # => true
  8. # dh.update :y => 2, :z => 4
  9. # dh.changed # => {:y => [:added, 2], :z => [:added, nil, 4]}
  10. # dh[:z] = 3
  11. # dh.changed # => {:y => [:added, 2], :z => [:replaced, 4, 3]}
  12. # dh.reject! { |key, value| value > 2 }
  13. # dh.changed # => {:y => [:added, 2], :z => [:deleted, 3, nil]}
  14. # dh.dirty? # => true
  15. # dh.clean!
  16. # dh.changed # => {}
  17. #
  18. # @note
  19. # The behaviour of the following methods remains to be defined: ==, eql?, hash
  20. class DirtyHash < Hash
  21. include Hash::Dirty
  22.  
  23. # Create a DirtyHash with prepopulated data.
  24. # The returned DirtyHash is clean.
  25. # If a second argument is provided, the first argument is used as default value.
  26. # A block is given, it is used as default_proc.
  27. #
  28. # @overload with(:prefilled => 'data')
  29. # @param [Hash, DirtyHash, #to_hash] prefilled_data
  30. # The data to fill the dirty hash with
  31. #
  32. # @overload with(:default_value, :prefilled => 'data')
  33. # @param [Object] default
  34. # The default value, it is returned instead of nil when trying to access a yet undefined key
  35. # @param [Hash, DirtyHash, #to_hash] prefilled_data
  36. # The data to fill the dirty hash with
  37. #
  38. # @overload with(:prefilled => 'data', &default_proc)
  39. # @param [Hash, DirtyHash, #to_hash] prefilled_data
  40. # The data to fill the dirty hash with
  41. # @yield [key, dirty_hash]
  42. # The default proc will be called with the hash object and the key, and should return the
  43. # default value. It is the block's responsibility to store the value in the hash if required.
  44. #
  45. # @example
  46. # dh1 = DirtyHash#with :x => "hello", :y => "world" # => DirtyHash{:x=>"hello",:y=>"world"}
  47. # dh2 = DirtyHash#with "foo", :x => "hello" # => DirtyHash{:x=>"hello"}
  48. # dh2[:undefined] # => "foo"
  49. # dh3 = DirtyHash#with :x => 1 do |dh,key| dh[key] = "bar" end
  50. # dh3[:becoming_defined] # => "bar"
  51. # dh3 # => DirtyHash{:x=>1,:becoming_defined=>"bar"}
  52. #
  53. # @see DirtyHash::new
  54. def self.with(*args, &block)
  55. raise ArgumentError, "wrong number of arguments (0 for 1)" if args.empty?
  56. prefilled_data = args.pop
  57. dirty_hash = new(*args, &block)
  58. unless prefilled_data.is_a?(Hash) then
  59. if prefilled_data.respond_to?(:to_hash) then
  60. prefilled_data = prefilled_data.to_hash
  61. else
  62. raise ArgumentError, "prefilled_data must respond to to_hash"
  63. end
  64. end
  65. dirty_hash.update(prefilled_data)
  66. dirty_hash.clean_changes!
  67.  
  68. dirty_hash
  69. end
  70.  
  71. def self.[](*)
  72. dirty_hash = super
  73. dirty_hash.send :initialize_dirty
  74. dirty_hash.clean_changes!
  75.  
  76. dirty_hash
  77. end
  78. end
Add Comment
Please, Sign In to add comment