# \[code\] Automatic Observer attachment at beginning of session

**URL:** <https://forums.sketchup.com/t/code-automatic-observer-attachment-at-beginning-of-session/189889>\
**Category:** Ruby API\
**Created:** [February 15, 2022, 1:15am UTC](https://forums.sketchup.com/t/code-automatic-observer-attachment-at-beginning-of-session/189889 "2022-02-15T01:15:23Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![DanRathbun](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/danrathbun/32/500_2.png) [@DanRathbun](https://forums.sketchup.com/u/DanRathbun)\
**Post date:** [February 15, 2022, 1:15am UTC](https://forums.sketchup.com/t/code-automatic-observer-attachment-at-beginning-of-session/189889/1 "2022-02-15T01:15:23Z")

</div>

This was [previously hidden](https://forums.sketchup.com/t/how-can-i-run-my-file-cpp-c-file-as-a-cron-job-when-i-alter-my-skp-file/188485/3) in the SDK category as a response to a mixed code extension.

**I have moved it here into the Ruby category.**

This also serves as the example for what was discussed in topic:

- [Observers that persist between Sketchup sessions?](https://forums.sketchup.com/t/observers-that-persist-between-sketchup-sessions/6111)

* * *

[Attach\_Model\_Observers.rb](https://forums.sketchup.com/uploads/short-url/rhbG3rxJDM5jm7En7Xgm0U06fKL.rb) (3.8 KB)

```ruby
# encoding: UTF-8

module SomeAuthor # <<---<<< Change to your toplevel namespace module
  module SomeNiftyExtension # <<---<<< Change to your extension submodule

    extend self

    def attach(model)
      model.add_observer(ModelSpy.new(model))
    end

    def expectsStartupModelNotifications
      true
    end

    def onNewModel(model)
      attach(model)
    end

    def onOpenModel(model)
      attach(model)
    end

    def onQuit()
      # execute onQuit tasks
    end

    class ModelSpy < Sketchup::ModelObserver
      attr_reader :model
      def initialize(model)
        puts "#{self.class.name}\n in '#{ __method__ }'"
        @model = model
        # Hash to hold observer references:
        @spy = {}
        # Add all of the implemented observers to model collections:
        model.definitions.add_observer(
          @spy[:definitions]= DefinitionsSpy.new(model.definitions)
        )
        # ... etc, ... same for Entities, Materials, Layers (if defined) ...
      end
      #
      ### ... ModelObserver callback method definitions ...
      #
    end # class

    class DefinitionSpy < Sketchup::DefinitionObserver
      def initialize(definition)
        puts "#{self.class.name}\n in '#{ __method__ }'"
        # On model load, attach observers to each existing instance:
        definition.instances.each { |instance|
          instance.add_observer(InstanceSpy.new)
          instance.add_observer(EntitySpy.new)
        }
      end
      def onComponentInstanceAdded(definition, instance)
        puts "#{self.class.name}\n in '#{ __method__ }':"
        puts " #{definition.name}: #{instance}"
        # Attach appropriate observers to the new instance:
        instance.add_observer(InstanceSpy.new)
        instance.add_observer(EntitySpy.new)
        # Do something with the new instance ...
      end
    end # class

    class DefinitionsSpy < Sketchup::DefinitionsObserver
      def initialize(definitions)
        puts "#{self.class.name}\n in '#{ __method__ }'"
        # On model load, attach an observer to each existing definition:
        definitions.each { |definition|
          definition.add_observer(DefinitionSpy.new(definition))
        }
      end
      def onComponentAdded(definitions, definition)
        puts "#{self.class.name}\n in '#{ __method__ }': #{definition}"
        # Attach an observer to the new definition:
        definition.add_observer(DefinitionSpy.new(definition))
        # Do something else with the new definition ...
      end
    end # class

    class EntitySpy < Sketchup::EntityObserver
      def initialize
        puts "#{self.class.name}\n in '#{ __method__ }'"
      end
      def onChangeEntity(entity)
        puts "#{self.class.name}\n in '#{ __method__ }': #{entity}"
        # Do something with the changed entity ...
      end
    end # class

    class InstanceSpy < Sketchup::InstanceObserver
      def initialize
        puts "#{self.class.name}\n in '#{ __method__ }'"
      end
      def onClose(instance)
        puts "#{self.class.name}\n in '#{ __method__ }': #{instance}"
        # Do something with the closed instance ...
        # The instance's internal coordinates are in local values.
      end
      def onOpen(instance)
        puts "#{self.class.name}\n in '#{ __method__ }': #{instance}"
        # Do something with the opened instance ...
        # All API methods will use and return WORLD coordinates !
      end
    end # class

    # .. other observer class definitions ...

    # RUN ONCE AT STARTUP:
    if !defined?(@loaded)

      # Define UI objects here ...

      # Attach this module as an AppObserver object:
      Sketchup.add_observer(self)

      # Mark this extension as loaded:
      @loaded = true
    end

  end # extension submodule
end # namespace module

```

* * *

Then when a component or group instance is moved, the [`onChangeEntity`](https://ruby.sketchup.com/Sketchup/EntityObserver.html#onChangeEntity-instance_method) callback method in the `EntitySpy` will get called.

**NOTE** : The `puts` statements like `puts "#{self.class.name}\n in '#{ __method__ }'"` sending output to the Console are just for testing. They can be deleted, commented out OR a conditional `if @debug` added at the end. (In the latter case you’ll need to define a `@debug` boolean variable at the top of the extension submodule.)

---

<div class="post-metadata">

**Author:** ![DanRathbun](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/danrathbun/32/500_2.png) [@DanRathbun](https://forums.sketchup.com/u/DanRathbun)\
**Post date:** [February 15, 2022, 1:15am UTC](https://forums.sketchup.com/t/code-automatic-observer-attachment-at-beginning-of-session/189889/2 "2022-02-15T01:15:47Z")

</div>

More information … (in progress) …
