Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- module KeyValueObserving
- attr_accessor :bindings
- def self.included(base)
- base.extend(ClassMethods)
- base.extend(SharedMethods)
- end
- module SharedMethods
- def did_change_value_for(attribute)
- puts "updated value for #{attribute} on #{self}"
- bindings_for(attribute).each do |binding|
- binding.object.send("#{binding.attribute}=", binding.key_path.target_property)
- end
- end
- end
- include SharedMethods
- module ClassMethods
- def kvc_accessor(*accessors)
- accessors.each do |accessor|
- define_method accessor do
- instance_variable_get "@#{accessor}"
- end
- define_method :"#{accessor}=" do |value|
- instance_variable_set "@#{accessor}", value
- did_change_value_for(accessor.to_s)
- end
- end
- end
- end
- end
- module Bindable
- def self.included(base)
- base.extend(SharedMethods)
- end
- attr_accessor :bindings
- module SharedMethods
- def bind(attribute,path)
- binding = Ribbon.new(self,attribute,path)
- self.send("#{attribute}=", binding.key_path.target_property)
- return binding
- end
- def bindings
- @bindings
- end
- def bindings_for(attribute)
- @bindings ||= {}
- @bindings[attribute] || []
- end
- def add_binding_for_attribute(binding,attribute)
- @bindings ||= {}
- @bindings[attribute] ? @bindings[attribute] << binding : @bindings[attribute] = [binding]
- end
- end
- include SharedMethods
- end
- class KeyPath
- def initialize(path)
- @path = path
- end
- def step_through(path)
- callee = Object.module_eval(path.shift)
- while caller = path.shift
- callee = callee.send(caller)
- end
- return callee
- end
- def target_object
- step_through(@path.split('.')[0..-2])
- end
- def target_property_name
- @path.split('.').last
- end
- def target_property
- step_through(@path.split('.'))
- end
- end
- class Ribbon
- attr_reader :key_path, :object, :attribute
- def initialize(object, attribute, key_path)
- @object = object
- @attribute = attribute
- @key_path = KeyPath.new(key_path)
- @bound_object = @key_path.target_object
- @bound_property = @key_path.target_property_name
- self.connect
- end
- def connect
- @bound_object.add_binding_for_attribute(self,@bound_property)
- end
- end
- class Controller
- include KeyValueObserving
- include Bindable
- def self.kvc_accessor(*accessors)
- accessors.each do |accessor|
- define_method accessor do
- instance_variable_get "@#{accessor}"
- end
- define_method :"#{accessor}=" do |value|
- instance_variable_set "@#{accessor}", value
- did_change_value_for(accessor.to_s)
- end
- m = Module.new do
- define_method accessor do
- self.shared_instance.send(accessor)
- end
- define_method :"#{accessor}=" do |value|
- self.shared_instance.send(:"#{accessor}=", value)
- did_change_value_for(accessor.to_s)
- end
- end
- self.extend(m)
- end
- end
- def self.shared_instance
- @shared_instance ||= self.new
- end
- end
- class ArrayController < Controller
- kvc_accessor :arranged_objects, :selection
- end
- class Model
- include Bindable
- include KeyValueObserving
- end
- class View
- include KeyValueObserving
- include Bindable
- kvc_accessor :data_source
- def initialize(options={:bind => {}})
- options[:bind].each do |property,path|
- bind property, path
- end
- end
- def did_change_value_for(attribute)
- redraw
- end
- def redraw
- puts "I was updated and redrew!"
- end
- end
- class Note < Model
- @data = [Note.new,Note.new,Note.new]
- def self.all
- @data
- end
- def self.all=(ary)
- @data = ary
- self.did_change_value_for('all')
- end
- end
- class NotesController < ArrayController
- shared_instance
- bind 'arranged_objects', 'Note.all'
- end
- # v = NoteList.new({:bind => {'data_source' => 'NotesController.arranged_objects'}})
- class NoteList < View
- end
Add Comment
Please, Sign In to add comment