Array#modified

I'm looking for a simple and short solution/library that does this:

a = []

def a.modified
puts "Array a changed"
end

a << 'x'
puts a
a[0] = 'y'
puts a

----OUTPUT----
Array a changed
x
Array a changed
y

···

--
Posted via http://www.ruby-forum.com/.

Juozas Gaigalas wrote:

I'm looking for a simple and short solution/library that does this:

(snip)

----OUTPUT----
Array a changed
x
Array a changed
y

Check out the Observable class in the standard library.

···

--
Posted via http://www.ruby-forum.com/\.

You can sort of do this, but an object does not know what variable(s) it is
assigned to, so you will never be able to get the "Array a changed" message
from it directly. Try the following, however:

module ArrayWatch
  def is_modified?
    @modified
  end

  def reset_modified
    @modified = false
  end

  def =(k, v)
    @modified = true
    super(k, v)
  end

  def <<(v)
    @modified = true
    super(v)
  end

  def concat(v)
    @modified = true
    super(v)
  end

  def push(*v)
    @modified = true
    super(*v)
  end

  def unshift(*v)
    @modified = true
    super(*v)
  end

  def replace(v)
    @modified = true
    super(v)
  end

  def slice!(*v)
    @modified = true
    super(*v)
  end

  def compact!
    @modified = true
    super
  end

  def sort!(&block)
    @modified = true
    super &block
  end

  def uniq!
    @modified = true
    super
  end

  def reverse!
    @modified = true
    super
  end

  def flatten!
    @modified = true
    super
  end

  def collect!(&block)
    @modified = true
    super &block
  end

  def map!(&block)
    @modified = true
    super &block
  end

  def delete_at(i)
    @modified = true
    super(i)
  end

  def delete(v, &block)
    @modified = true
    super(v, &block)
  end

  def delete_if(&block)
    @modified = true
    super &block
  end

  def reject!(&block)
    @modified = true
    super &block
  end

  def shift
    @modified = true
    super
  end

  def pop
    @modified = true
    super
  end

end

a =
a.extend ArrayWatch

def a.to_s
  "a #{ is_modified? ? 'is' : 'is not' } modified"
end

puts a
a << 'x'
puts a
a.reset_modified
puts a
a[0] = 'y'
puts a

--Greg

···

On Mon, Jan 15, 2007 at 10:52:37PM +0900, Juozas Gaigalas wrote:

I'm looking for a simple and short solution/library that does this:

a =

def a.modified
puts "Array a changed"
end

a << 'x'
puts a
a[0] = 'y'
puts a

----OUTPUT----
Array a changed
x
Array a changed
y

Juozas Gaigalas wrote:

I'm looking for a simple and short solution/library that does this:

a =

def a.modified
puts "Array a changed"
end

a << 'x'
puts a
a[0] = 'y'
puts a

----OUTPUT----
Array a changed
x
Array a changed
y

class Changed
  def initialize(obj, &changed)
    @obj = obj
    @changed = changed
  end

  def method_missing(id, *a, &b)
    obj_before = @obj.clone
    @obj.__send__(id, *a, &b)
    if obj_before != @obj
      @changed[@obj, id, a, b]
    end
  end
end

if $0 == __FILE__
  a =
  c = Changed.new(a) do |obj, id, args, block|
    STDOUT << "#{obj.inspect} changed by #{id}"
    STDOUT << "(#{args.map { |x| x.inspect } * ','})" unless args.empty?
    STDOUT << "\n"
  end
  c << 1
  # [1] changed by <<(1)
  c.to_s
  c << 2
  # [1, 2] changed by <<(2)
  c.delete 2
  # [1] changed by delete(2)
  c.delete 2
  c << 3
  # [1, 3] changed by <<(3)
  c[0] = 4
  # [4, 3] changed by =(0,4)
  c.replace [6,6,6]
  # [6, 6, 6] changed by replace([6, 6, 6])
  c.clear
  # changed by clear
end

···

--
Florian Frank

Tim Hunter wrote:

Juozas Gaigalas wrote:

I'm looking for a simple and short solution/library that does this:

(snip)

----OUTPUT----
Array a changed
x
Array a changed
y

Check out the Observable class in the standard library.

Thanks for your prompt reply. Unfortunately Observable is not what I'm
looking for. It requires manually setting "changed" state to true on
every operation that modifies the array. I'm looking for something that
overrides all of the methods that can modify an array (<<, pop, shift,
push, =, filter, etc.) then calls the old method and finally invokes
the "modified" callback.

I'm assuming something like this exists (specifically for the Array
class). I could write it myself, but I'd prefer to reuse existing code.

···

--
Posted via http://www.ruby-forum.com/\.

...

Alternative approach would be to use Delegator to wrap an Array instance.

OP, what are you trying to achieve? What is the problem you are trying to solve?

Kind regards

  robert

···

On 15.01.2007 15:20, Gregory Seidman wrote:

On Mon, Jan 15, 2007 at 10:52:37PM +0900, Juozas Gaigalas wrote:

I'm looking for a simple and short solution/library that does this:

a =

def a.modified
puts "Array a changed"
end

a << 'x'
puts a
a[0] = 'y'
puts a

----OUTPUT----
Array a changed
x
Array a changed
y

You can sort of do this, but an object does not know what variable(s) it is
assigned to, so you will never be able to get the "Array a changed" message
from it directly. Try the following, however:

module ArrayWatch
  def is_modified?
    @modified
  end

  

class Changed
  def initialize(obj, &changed)
    @obj = obj
    @changed = changed
  end

  def method_missing(id, *a, &b)
    obj_before = @obj.clone
    @obj.__send__(id, *a, &b)
    if obj_before != @obj
      @changed[@obj, id, a, b]
    end
  end
end

I like this solution because it's short. However, it requires cloning
the array every time a method is invoked on it, it seems that it would
slow it down too much for my needs. I'm not sure.

I think I'll google for "ruby event framework" as Marc suggested.

···

--
Posted via http://www.ruby-forum.com/\.

Juozas Gaigalas wrote:

..., but I'd prefer to reuse existing code.

Maybe also check out some design patterns (state pattern, observer
pattern):

http://rightfootin.blogspot.com/2006/08/implementing-state-pattern-in-ruby.html

http://cwilliams.textdriven.com/articles/2006/11/02/patterns-in-ruby-observer-pattern

Cheers,
verno

···

--
Posted via http://www.ruby-forum.com/\.