glimmer 2.4.0 → 2.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/CHANGELOG.md +23 -0
 - data/README.md +229 -139
 - data/VERSION +1 -1
 - data/glimmer.gemspec +90 -89
 - data/lib/glimmer/data_binding/model_binding.rb +19 -8
 - data/lib/glimmer/data_binding/observable_array.rb +21 -15
 - data/lib/glimmer/data_binding/observable_hash.rb +3 -61
 - data/lib/glimmer/data_binding/observable_hashable.rb +75 -0
 - data/lib/glimmer/data_binding/observable_model.rb +27 -35
 - data/lib/glimmer/data_binding/observer.rb +16 -14
 - metadata +10 -8
 
    
        data/glimmer.gemspec
    CHANGED
    
    | 
         @@ -1,89 +1,90 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # Generated by jeweler
         
     | 
| 
       2 
     | 
    
         
            -
            # DO NOT EDIT THIS FILE DIRECTLY
         
     | 
| 
       3 
     | 
    
         
            -
            # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
         
     | 
| 
       4 
     | 
    
         
            -
            # -*- encoding: utf-8 -*-
         
     | 
| 
       5 
     | 
    
         
            -
            # stub: glimmer 2. 
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
       7 
     | 
    
         
            -
            Gem::Specification.new do |s|
         
     | 
| 
       8 
     | 
    
         
            -
              s.name = "glimmer".freeze
         
     | 
| 
       9 
     | 
    
         
            -
              s.version = "2. 
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
     | 
    
         
            -
              s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
         
     | 
| 
       12 
     | 
    
         
            -
              s.require_paths = ["lib".freeze]
         
     | 
| 
       13 
     | 
    
         
            -
              s.authors = ["AndyMaleh".freeze]
         
     | 
| 
       14 
     | 
    
         
            -
              s.date = "2021- 
     | 
| 
       15 
     | 
    
         
            -
              s.description = "Glimmer is a Ruby DSL Framework for Ruby GUI and More, consisting of a DSL Engine and an Observable / Observer / Data-Binding Library (including Observable Model, Observable Array, and Observable Hash). Used in Glimmer DSL for SWT (JRuby Desktop Development GUI Framework), Glimmer DSL for Tk (Ruby Desktop Development GUI Library), Glimmer DSL for LibUI (Prerequisite-Free Ruby Desktop Development GUI Library), Glimmer DSL for  
     | 
| 
       16 
     | 
    
         
            -
              s.email = "andy.am@gmail.com".freeze
         
     | 
| 
       17 
     | 
    
         
            -
              s.extra_rdoc_files = [
         
     | 
| 
       18 
     | 
    
         
            -
                "CHANGELOG.md",
         
     | 
| 
       19 
     | 
    
         
            -
                "LICENSE.txt",
         
     | 
| 
       20 
     | 
    
         
            -
                "README.md"
         
     | 
| 
       21 
     | 
    
         
            -
              ]
         
     | 
| 
       22 
     | 
    
         
            -
              s.files = [
         
     | 
| 
       23 
     | 
    
         
            -
                "CHANGELOG.md",
         
     | 
| 
       24 
     | 
    
         
            -
                "CONTRIBUTING.md",
         
     | 
| 
       25 
     | 
    
         
            -
                "LICENSE.txt",
         
     | 
| 
       26 
     | 
    
         
            -
                "PROCESS.md",
         
     | 
| 
       27 
     | 
    
         
            -
                "README.md",
         
     | 
| 
       28 
     | 
    
         
            -
                "VERSION",
         
     | 
| 
       29 
     | 
    
         
            -
                "glimmer.gemspec",
         
     | 
| 
       30 
     | 
    
         
            -
                "lib/glimmer.rb",
         
     | 
| 
       31 
     | 
    
         
            -
                "lib/glimmer/config.rb",
         
     | 
| 
       32 
     | 
    
         
            -
                "lib/glimmer/data_binding/model_binding.rb",
         
     | 
| 
       33 
     | 
    
         
            -
                "lib/glimmer/data_binding/observable.rb",
         
     | 
| 
       34 
     | 
    
         
            -
                "lib/glimmer/data_binding/observable_array.rb",
         
     | 
| 
       35 
     | 
    
         
            -
                "lib/glimmer/data_binding/observable_hash.rb",
         
     | 
| 
       36 
     | 
    
         
            -
                "lib/glimmer/data_binding/ 
     | 
| 
       37 
     | 
    
         
            -
                "lib/glimmer/data_binding/ 
     | 
| 
       38 
     | 
    
         
            -
                "lib/glimmer/data_binding/ 
     | 
| 
       39 
     | 
    
         
            -
                "lib/glimmer/ 
     | 
| 
       40 
     | 
    
         
            -
                "lib/glimmer/dsl/ 
     | 
| 
       41 
     | 
    
         
            -
                "lib/glimmer/dsl/ 
     | 
| 
       42 
     | 
    
         
            -
                "lib/glimmer/dsl/ 
     | 
| 
       43 
     | 
    
         
            -
                "lib/glimmer/dsl/ 
     | 
| 
       44 
     | 
    
         
            -
                "lib/glimmer/dsl/ 
     | 
| 
       45 
     | 
    
         
            -
                "lib/glimmer/dsl/ 
     | 
| 
       46 
     | 
    
         
            -
                "lib/glimmer/dsl/ 
     | 
| 
       47 
     | 
    
         
            -
                "lib/glimmer/ 
     | 
| 
       48 
     | 
    
         
            -
                "lib/glimmer/ 
     | 
| 
       49 
     | 
    
         
            -
                "lib/glimmer/ 
     | 
| 
       50 
     | 
    
         
            -
                "lib/glimmer/ 
     | 
| 
       51 
     | 
    
         
            -
             
     | 
| 
       52 
     | 
    
         
            -
               
     | 
| 
       53 
     | 
    
         
            -
              s. 
     | 
| 
       54 
     | 
    
         
            -
              s. 
     | 
| 
       55 
     | 
    
         
            -
              s. 
     | 
| 
       56 
     | 
    
         
            -
             
     | 
| 
       57 
     | 
    
         
            -
             
     | 
| 
       58 
     | 
    
         
            -
             
     | 
| 
       59 
     | 
    
         
            -
             
     | 
| 
       60 
     | 
    
         
            -
             
     | 
| 
       61 
     | 
    
         
            -
             
     | 
| 
       62 
     | 
    
         
            -
             
     | 
| 
       63 
     | 
    
         
            -
                s.add_runtime_dependency(%q< 
     | 
| 
       64 
     | 
    
         
            -
                s. 
     | 
| 
       65 
     | 
    
         
            -
                s.add_development_dependency(%q<rspec>.freeze, ["~> 3.5.0"])
         
     | 
| 
       66 
     | 
    
         
            -
                s.add_development_dependency(%q< 
     | 
| 
       67 
     | 
    
         
            -
                s.add_development_dependency(%q< 
     | 
| 
       68 
     | 
    
         
            -
                s.add_development_dependency(%q< 
     | 
| 
       69 
     | 
    
         
            -
                s.add_development_dependency(%q< 
     | 
| 
       70 
     | 
    
         
            -
                s.add_development_dependency(%q< 
     | 
| 
       71 
     | 
    
         
            -
                s.add_development_dependency(%q< 
     | 
| 
       72 
     | 
    
         
            -
                s.add_development_dependency(%q<simplecov 
     | 
| 
       73 
     | 
    
         
            -
                s.add_development_dependency(%q< 
     | 
| 
       74 
     | 
    
         
            -
             
     | 
| 
       75 
     | 
    
         
            -
             
     | 
| 
       76 
     | 
    
         
            -
                s.add_dependency(%q< 
     | 
| 
       77 
     | 
    
         
            -
                s.add_dependency(%q< 
     | 
| 
       78 
     | 
    
         
            -
                s.add_dependency(%q<rspec>.freeze, ["~> 3.5.0"])
         
     | 
| 
       79 
     | 
    
         
            -
                s.add_dependency(%q< 
     | 
| 
       80 
     | 
    
         
            -
                s.add_dependency(%q< 
     | 
| 
       81 
     | 
    
         
            -
                s.add_dependency(%q< 
     | 
| 
       82 
     | 
    
         
            -
                s.add_dependency(%q< 
     | 
| 
       83 
     | 
    
         
            -
                s.add_dependency(%q< 
     | 
| 
       84 
     | 
    
         
            -
                s.add_dependency(%q< 
     | 
| 
       85 
     | 
    
         
            -
                s.add_dependency(%q<simplecov 
     | 
| 
       86 
     | 
    
         
            -
                s.add_dependency(%q< 
     | 
| 
       87 
     | 
    
         
            -
             
     | 
| 
       88 
     | 
    
         
            -
            end
         
     | 
| 
       89 
     | 
    
         
            -
             
     | 
| 
      
 1 
     | 
    
         
            +
            # Generated by jeweler
         
     | 
| 
      
 2 
     | 
    
         
            +
            # DO NOT EDIT THIS FILE DIRECTLY
         
     | 
| 
      
 3 
     | 
    
         
            +
            # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
         
     | 
| 
      
 4 
     | 
    
         
            +
            # -*- encoding: utf-8 -*-
         
     | 
| 
      
 5 
     | 
    
         
            +
            # stub: glimmer 2.5.3 ruby lib
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            Gem::Specification.new do |s|
         
     | 
| 
      
 8 
     | 
    
         
            +
              s.name = "glimmer".freeze
         
     | 
| 
      
 9 
     | 
    
         
            +
              s.version = "2.5.3"
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
              s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
         
     | 
| 
      
 12 
     | 
    
         
            +
              s.require_paths = ["lib".freeze]
         
     | 
| 
      
 13 
     | 
    
         
            +
              s.authors = ["AndyMaleh".freeze]
         
     | 
| 
      
 14 
     | 
    
         
            +
              s.date = "2021-12-07"
         
     | 
| 
      
 15 
     | 
    
         
            +
              s.description = "Glimmer is a Ruby DSL Framework for Ruby GUI and More, consisting of a DSL Engine and an Observable / Observer / Data-Binding Library (including Observable Model, Observable Array, and Observable Hash). Used in Glimmer DSL for SWT (JRuby Desktop Development GUI Framework), Glimmer DSL for Opal (Pure Ruby Web GUI and Auto-Webifier of Desktop Apps), Glimmer DSL for Tk (Ruby Desktop Development GUI Library), Glimmer DSL for LibUI (Prerequisite-Free Ruby Desktop Development GUI Library), Glimmer DSL for GTK (Ruby-GNOME Desktop Development GUI Library), Glimmer DSL for XML (& HTML), and Glimmer DSL for CSS.".freeze
         
     | 
| 
      
 16 
     | 
    
         
            +
              s.email = "andy.am@gmail.com".freeze
         
     | 
| 
      
 17 
     | 
    
         
            +
              s.extra_rdoc_files = [
         
     | 
| 
      
 18 
     | 
    
         
            +
                "CHANGELOG.md",
         
     | 
| 
      
 19 
     | 
    
         
            +
                "LICENSE.txt",
         
     | 
| 
      
 20 
     | 
    
         
            +
                "README.md"
         
     | 
| 
      
 21 
     | 
    
         
            +
              ]
         
     | 
| 
      
 22 
     | 
    
         
            +
              s.files = [
         
     | 
| 
      
 23 
     | 
    
         
            +
                "CHANGELOG.md",
         
     | 
| 
      
 24 
     | 
    
         
            +
                "CONTRIBUTING.md",
         
     | 
| 
      
 25 
     | 
    
         
            +
                "LICENSE.txt",
         
     | 
| 
      
 26 
     | 
    
         
            +
                "PROCESS.md",
         
     | 
| 
      
 27 
     | 
    
         
            +
                "README.md",
         
     | 
| 
      
 28 
     | 
    
         
            +
                "VERSION",
         
     | 
| 
      
 29 
     | 
    
         
            +
                "glimmer.gemspec",
         
     | 
| 
      
 30 
     | 
    
         
            +
                "lib/glimmer.rb",
         
     | 
| 
      
 31 
     | 
    
         
            +
                "lib/glimmer/config.rb",
         
     | 
| 
      
 32 
     | 
    
         
            +
                "lib/glimmer/data_binding/model_binding.rb",
         
     | 
| 
      
 33 
     | 
    
         
            +
                "lib/glimmer/data_binding/observable.rb",
         
     | 
| 
      
 34 
     | 
    
         
            +
                "lib/glimmer/data_binding/observable_array.rb",
         
     | 
| 
      
 35 
     | 
    
         
            +
                "lib/glimmer/data_binding/observable_hash.rb",
         
     | 
| 
      
 36 
     | 
    
         
            +
                "lib/glimmer/data_binding/observable_hashable.rb",
         
     | 
| 
      
 37 
     | 
    
         
            +
                "lib/glimmer/data_binding/observable_model.rb",
         
     | 
| 
      
 38 
     | 
    
         
            +
                "lib/glimmer/data_binding/observer.rb",
         
     | 
| 
      
 39 
     | 
    
         
            +
                "lib/glimmer/data_binding/shine.rb",
         
     | 
| 
      
 40 
     | 
    
         
            +
                "lib/glimmer/dsl/bind_expression.rb",
         
     | 
| 
      
 41 
     | 
    
         
            +
                "lib/glimmer/dsl/engine.rb",
         
     | 
| 
      
 42 
     | 
    
         
            +
                "lib/glimmer/dsl/expression.rb",
         
     | 
| 
      
 43 
     | 
    
         
            +
                "lib/glimmer/dsl/expression_handler.rb",
         
     | 
| 
      
 44 
     | 
    
         
            +
                "lib/glimmer/dsl/observe_expression.rb",
         
     | 
| 
      
 45 
     | 
    
         
            +
                "lib/glimmer/dsl/parent_expression.rb",
         
     | 
| 
      
 46 
     | 
    
         
            +
                "lib/glimmer/dsl/static_expression.rb",
         
     | 
| 
      
 47 
     | 
    
         
            +
                "lib/glimmer/dsl/top_level_expression.rb",
         
     | 
| 
      
 48 
     | 
    
         
            +
                "lib/glimmer/error.rb",
         
     | 
| 
      
 49 
     | 
    
         
            +
                "lib/glimmer/ext/module.rb",
         
     | 
| 
      
 50 
     | 
    
         
            +
                "lib/glimmer/invalid_keyword_error.rb",
         
     | 
| 
      
 51 
     | 
    
         
            +
                "lib/glimmer/shim/concurrent.rb"
         
     | 
| 
      
 52 
     | 
    
         
            +
              ]
         
     | 
| 
      
 53 
     | 
    
         
            +
              s.homepage = "http://github.com/AndyObtiva/glimmer".freeze
         
     | 
| 
      
 54 
     | 
    
         
            +
              s.licenses = ["MIT".freeze]
         
     | 
| 
      
 55 
     | 
    
         
            +
              s.rubygems_version = "3.2.22".freeze
         
     | 
| 
      
 56 
     | 
    
         
            +
              s.summary = "Glimmer - DSL Engine for Ruby GUI and More".freeze
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
              if s.respond_to? :specification_version then
         
     | 
| 
      
 59 
     | 
    
         
            +
                s.specification_version = 4
         
     | 
| 
      
 60 
     | 
    
         
            +
              end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
              if s.respond_to? :add_runtime_dependency then
         
     | 
| 
      
 63 
     | 
    
         
            +
                s.add_runtime_dependency(%q<array_include_methods>.freeze, ["~> 1.4.0"])
         
     | 
| 
      
 64 
     | 
    
         
            +
                s.add_runtime_dependency(%q<facets>.freeze, [">= 3.1.0", "< 4.0.0"])
         
     | 
| 
      
 65 
     | 
    
         
            +
                s.add_development_dependency(%q<rspec-mocks>.freeze, ["~> 3.5.0"])
         
     | 
| 
      
 66 
     | 
    
         
            +
                s.add_development_dependency(%q<rspec>.freeze, ["~> 3.5.0"])
         
     | 
| 
      
 67 
     | 
    
         
            +
                s.add_development_dependency(%q<puts_debuggerer>.freeze, ["~> 0.13"])
         
     | 
| 
      
 68 
     | 
    
         
            +
                s.add_development_dependency(%q<rake>.freeze, [">= 10.1.0", "< 14.0.0"])
         
     | 
| 
      
 69 
     | 
    
         
            +
                s.add_development_dependency(%q<jeweler>.freeze, [">= 2.0.0", "< 3.0.0"])
         
     | 
| 
      
 70 
     | 
    
         
            +
                s.add_development_dependency(%q<rdoc>.freeze, [">= 6.2.1", "< 7.0.0"])
         
     | 
| 
      
 71 
     | 
    
         
            +
                s.add_development_dependency(%q<coveralls>.freeze, [">= 0"])
         
     | 
| 
      
 72 
     | 
    
         
            +
                s.add_development_dependency(%q<simplecov>.freeze, ["~> 0.16.1"])
         
     | 
| 
      
 73 
     | 
    
         
            +
                s.add_development_dependency(%q<simplecov-lcov>.freeze, ["~> 0.7.0"])
         
     | 
| 
      
 74 
     | 
    
         
            +
                s.add_development_dependency(%q<rake-tui>.freeze, ["> 0"])
         
     | 
| 
      
 75 
     | 
    
         
            +
              else
         
     | 
| 
      
 76 
     | 
    
         
            +
                s.add_dependency(%q<array_include_methods>.freeze, ["~> 1.4.0"])
         
     | 
| 
      
 77 
     | 
    
         
            +
                s.add_dependency(%q<facets>.freeze, [">= 3.1.0", "< 4.0.0"])
         
     | 
| 
      
 78 
     | 
    
         
            +
                s.add_dependency(%q<rspec-mocks>.freeze, ["~> 3.5.0"])
         
     | 
| 
      
 79 
     | 
    
         
            +
                s.add_dependency(%q<rspec>.freeze, ["~> 3.5.0"])
         
     | 
| 
      
 80 
     | 
    
         
            +
                s.add_dependency(%q<puts_debuggerer>.freeze, ["~> 0.13"])
         
     | 
| 
      
 81 
     | 
    
         
            +
                s.add_dependency(%q<rake>.freeze, [">= 10.1.0", "< 14.0.0"])
         
     | 
| 
      
 82 
     | 
    
         
            +
                s.add_dependency(%q<jeweler>.freeze, [">= 2.0.0", "< 3.0.0"])
         
     | 
| 
      
 83 
     | 
    
         
            +
                s.add_dependency(%q<rdoc>.freeze, [">= 6.2.1", "< 7.0.0"])
         
     | 
| 
      
 84 
     | 
    
         
            +
                s.add_dependency(%q<coveralls>.freeze, [">= 0"])
         
     | 
| 
      
 85 
     | 
    
         
            +
                s.add_dependency(%q<simplecov>.freeze, ["~> 0.16.1"])
         
     | 
| 
      
 86 
     | 
    
         
            +
                s.add_dependency(%q<simplecov-lcov>.freeze, ["~> 0.7.0"])
         
     | 
| 
      
 87 
     | 
    
         
            +
                s.add_dependency(%q<rake-tui>.freeze, ["> 0"])
         
     | 
| 
      
 88 
     | 
    
         
            +
              end
         
     | 
| 
      
 89 
     | 
    
         
            +
            end
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
         @@ -30,9 +30,9 @@ module Glimmer 
     | 
|
| 
       30 
30 
     | 
    
         | 
| 
       31 
31 
     | 
    
         
             
                  attr_reader :binding_options, :property_name_expression
         
     | 
| 
       32 
32 
     | 
    
         | 
| 
       33 
     | 
    
         
            -
                  def initialize( 
     | 
| 
       34 
     | 
    
         
            -
                     
     | 
| 
       35 
     | 
    
         
            -
                    @property_name_expression =  
     | 
| 
      
 33 
     | 
    
         
            +
                  def initialize(*args)
         
     | 
| 
      
 34 
     | 
    
         
            +
                    binding_options = args.pop if args.size > 1 && args.last.is_a?(Hash)
         
     | 
| 
      
 35 
     | 
    
         
            +
                    @base_model, @property_name_expression = args
         
     | 
| 
       36 
36 
     | 
    
         
             
                    @binding_options = binding_options || Concurrent::Hash.new
         
     | 
| 
       37 
37 
     | 
    
         
             
                    if computed?
         
     | 
| 
       38 
38 
     | 
    
         
             
                      @computed_model_bindings = Concurrent::Array.new(computed_by.map do |computed_by_property_expression|
         
     | 
| 
         @@ -91,7 +91,7 @@ module Glimmer 
     | 
|
| 
       91 
91 
     | 
    
         
             
                  end
         
     | 
| 
       92 
92 
     | 
    
         | 
| 
       93 
93 
     | 
    
         
             
                  def nested_property?
         
     | 
| 
       94 
     | 
    
         
            -
                    property_name_expression.match(/[.\[]/)
         
     | 
| 
      
 94 
     | 
    
         
            +
                    property_name_expression.to_s.match(/[.\[]/)
         
     | 
| 
       95 
95 
     | 
    
         
             
                  end
         
     | 
| 
       96 
96 
     | 
    
         | 
| 
       97 
97 
     | 
    
         
             
                  def computed?
         
     | 
| 
         @@ -137,7 +137,7 @@ module Glimmer 
     | 
|
| 
       137 
137 
     | 
    
         
             
                          apply_processor(@binding_options[:after_read], converted_value)
         
     | 
| 
       138 
138 
     | 
    
         
             
                        end
         
     | 
| 
       139 
139 
     | 
    
         
             
                      end
         
     | 
| 
       140 
     | 
    
         
            -
                      observer_registration = model_binding_observer.observe(model, property_name, observation_options)
         
     | 
| 
      
 140 
     | 
    
         
            +
                      observer_registration = model_binding_observer.observe(*[model, property_name, observation_options].compact)
         
     | 
| 
       141 
141 
     | 
    
         
             
                      my_registration = observer.registration_for(self)
         
     | 
| 
       142 
142 
     | 
    
         
             
                      observer.add_dependent(my_registration => observer_registration)
         
     | 
| 
       143 
143 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -206,7 +206,7 @@ module Glimmer 
     | 
|
| 
       206 
206 
     | 
    
         
             
                  def call(value, *extra_args)
         
     | 
| 
       207 
207 
     | 
    
         
             
                    return if model.nil?
         
     | 
| 
       208 
208 
     | 
    
         
             
                    converted_value = value
         
     | 
| 
       209 
     | 
    
         
            -
                    invoke_property_writer(model, "#{property_name}=", converted_value) unless converted_value == evaluate_property
         
     | 
| 
      
 209 
     | 
    
         
            +
                    invoke_property_writer(model, model.is_a?(Hash) ? property_name : "#{property_name}=", converted_value) unless converted_value == evaluate_property || property_name.nil?
         
     | 
| 
       210 
210 
     | 
    
         
             
                  end
         
     | 
| 
       211 
211 
     | 
    
         | 
| 
       212 
212 
     | 
    
         
             
                  def evaluate_property
         
     | 
| 
         @@ -263,11 +263,18 @@ module Glimmer 
     | 
|
| 
       263 
263 
     | 
    
         
             
                      property_argument = property_argument.to_i if property_argument.match(/\d+/)
         
     | 
| 
       264 
264 
     | 
    
         
             
                      object.send(property_method, property_argument)
         
     | 
| 
       265 
265 
     | 
    
         
             
                    else
         
     | 
| 
       266 
     | 
    
         
            -
                       
     | 
| 
      
 266 
     | 
    
         
            +
                      if property_expression.nil?
         
     | 
| 
      
 267 
     | 
    
         
            +
                        object
         
     | 
| 
      
 268 
     | 
    
         
            +
                      elsif object.is_a?(Hash)
         
     | 
| 
      
 269 
     | 
    
         
            +
                        object[property_expression]
         
     | 
| 
      
 270 
     | 
    
         
            +
                      else
         
     | 
| 
      
 271 
     | 
    
         
            +
                        object.send(property_expression)
         
     | 
| 
      
 272 
     | 
    
         
            +
                      end
         
     | 
| 
       267 
273 
     | 
    
         
             
                    end
         
     | 
| 
       268 
274 
     | 
    
         
             
                  end
         
     | 
| 
       269 
275 
     | 
    
         | 
| 
       270 
276 
     | 
    
         
             
                  def invoke_property_writer(object, property_expression, value)
         
     | 
| 
      
 277 
     | 
    
         
            +
                    return if property_expression.nil?
         
     | 
| 
       271 
278 
     | 
    
         
             
                    raise "Cannot invoke `#{property_expression}` because ModelBinding#binding_options[:read_only]=true" if @binding_options[:read_only]
         
     | 
| 
       272 
279 
     | 
    
         
             
                    apply_processor(@binding_options[:before_write], value)
         
     | 
| 
       273 
280 
     | 
    
         
             
                    converted_value = convert_on_write(value)
         
     | 
| 
         @@ -277,7 +284,11 @@ module Glimmer 
     | 
|
| 
       277 
284 
     | 
    
         
             
                      property_argument = property_argument.to_i if property_argument.match(/\d+/)
         
     | 
| 
       278 
285 
     | 
    
         
             
                      object.send(property_method, property_argument, converted_value)
         
     | 
| 
       279 
286 
     | 
    
         
             
                    else
         
     | 
| 
       280 
     | 
    
         
            -
                      object. 
     | 
| 
      
 287 
     | 
    
         
            +
                      if object.is_a?(Hash)
         
     | 
| 
      
 288 
     | 
    
         
            +
                        object[property_expression] = converted_value
         
     | 
| 
      
 289 
     | 
    
         
            +
                      else
         
     | 
| 
      
 290 
     | 
    
         
            +
                        object.send(property_expression, converted_value)
         
     | 
| 
      
 291 
     | 
    
         
            +
                      end
         
     | 
| 
       281 
292 
     | 
    
         
             
                    end
         
     | 
| 
       282 
293 
     | 
    
         
             
                    apply_processor(@binding_options[:after_write], converted_value)
         
     | 
| 
       283 
294 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -50,15 +50,19 @@ module Glimmer 
     | 
|
| 
       50 
50 
     | 
    
         
             
                    element_properties = args
         
     | 
| 
       51 
51 
     | 
    
         
             
                    element_properties = element_properties.flatten.compact.uniq
         
     | 
| 
       52 
52 
     | 
    
         
             
                    return observer if has_observer?(observer) && has_observer_element_properties?(observer, element_properties)
         
     | 
| 
       53 
     | 
    
         
            -
                    property_observer_list  
     | 
| 
       54 
     | 
    
         
            -
                    observer_element_properties[observer] = element_properties_for(observer) + Concurrent:: 
     | 
| 
      
 53 
     | 
    
         
            +
                    property_observer_list[observer] = options
         
     | 
| 
      
 54 
     | 
    
         
            +
                    observer_element_properties[observer] = Concurrent::Set.new(Concurrent::Array.new(element_properties_for(observer).to_a) + Concurrent::Array.new(element_properties)) # converting to Array as a workaround to jruby-9.3.2.0 issue TODO remove this workaround when no longer needed
         
     | 
| 
      
 55 
     | 
    
         
            +
                    if !options.empty? && options[:recursive].is_a?(Integer)
         
     | 
| 
      
 56 
     | 
    
         
            +
                      options = options.clone
         
     | 
| 
      
 57 
     | 
    
         
            +
                      options[:recursive] = options[:recursive] - 1
         
     | 
| 
      
 58 
     | 
    
         
            +
                    end
         
     | 
| 
       55 
59 
     | 
    
         
             
                    each { |element| add_element_observer(element, observer, options) }
         
     | 
| 
       56 
60 
     | 
    
         
             
                    observer
         
     | 
| 
       57 
61 
     | 
    
         
             
                  end
         
     | 
| 
       58 
62 
     | 
    
         | 
| 
       59 
     | 
    
         
            -
                  def add_element_observers(element,  
     | 
| 
       60 
     | 
    
         
            -
                    property_observer_list.each do |observer|
         
     | 
| 
       61 
     | 
    
         
            -
                      add_element_observer(element, observer, options)
         
     | 
| 
      
 63 
     | 
    
         
            +
                  def add_element_observers(element, general_options = {})
         
     | 
| 
      
 64 
     | 
    
         
            +
                    property_observer_list.each do |observer, options|
         
     | 
| 
      
 65 
     | 
    
         
            +
                      add_element_observer(element, observer, options.merge(general_options))
         
     | 
| 
       62 
66 
     | 
    
         
             
                    end
         
     | 
| 
       63 
67 
     | 
    
         
             
                  end
         
     | 
| 
       64 
68 
     | 
    
         | 
| 
         @@ -66,14 +70,16 @@ module Glimmer 
     | 
|
| 
       66 
70 
     | 
    
         
             
                    element_properties_for(observer).each do |property|
         
     | 
| 
       67 
71 
     | 
    
         
             
                      observer.observe(element, property, options)
         
     | 
| 
       68 
72 
     | 
    
         
             
                    end
         
     | 
| 
       69 
     | 
    
         
            -
                     
     | 
| 
      
 73 
     | 
    
         
            +
                    if element.is_a?(Array) && (options[:recursive] == true || (options[:recursive].is_a?(Integer) && options[:recursive] >= 0))
         
     | 
| 
      
 74 
     | 
    
         
            +
                      ensure_array_object_observer(element, options)
         
     | 
| 
      
 75 
     | 
    
         
            +
                    end
         
     | 
| 
       70 
76 
     | 
    
         
             
                  end
         
     | 
| 
       71 
77 
     | 
    
         | 
| 
       72 
78 
     | 
    
         
             
                  def ensure_array_object_observer(object, options)
         
     | 
| 
       73 
79 
     | 
    
         
             
                    return unless object&.is_a?(Array)
         
     | 
| 
       74 
80 
     | 
    
         
             
                    array_object_observer = array_object_observer_for(object)
         
     | 
| 
       75 
81 
     | 
    
         
             
                    array_observer_registration = array_object_observer.observe(object, options)
         
     | 
| 
       76 
     | 
    
         
            -
                    property_observer_list.each do |observer|
         
     | 
| 
      
 82 
     | 
    
         
            +
                    property_observer_list.each do |observer, options|
         
     | 
| 
       77 
83 
     | 
    
         
             
                      my_registration = observer.registration_for(self)
         
     | 
| 
       78 
84 
     | 
    
         
             
                      observer.add_dependent(my_registration => array_observer_registration)
         
     | 
| 
       79 
85 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -91,7 +97,7 @@ module Glimmer 
     | 
|
| 
       91 
97 
     | 
    
         
             
                    element_properties = element_properties.flatten.compact.uniq
         
     | 
| 
       92 
98 
     | 
    
         
             
                    if !element_properties.empty?
         
     | 
| 
       93 
99 
     | 
    
         
             
                      old_element_properties = element_properties_for(observer)
         
     | 
| 
       94 
     | 
    
         
            -
                      observer_element_properties[observer] = element_properties_for(observer) - Concurrent:: 
     | 
| 
      
 100 
     | 
    
         
            +
                      observer_element_properties[observer] = Concurrent::Set.new(Concurrent::Array.new(element_properties_for(observer).to_a) - Concurrent::Array.new(element_properties)) # TODO remove this workaround when no longer needed (it is for jruby-9.3.2.0 issue)
         
     | 
| 
       95 
101 
     | 
    
         
             
                      each { |element| element_properties.each { |property| observer.unobserve(element, property) } }
         
     | 
| 
       96 
102 
     | 
    
         
             
                    end
         
     | 
| 
       97 
103 
     | 
    
         
             
                    if element_properties_for(observer).empty?
         
     | 
| 
         @@ -103,7 +109,7 @@ module Glimmer 
     | 
|
| 
       103 
109 
     | 
    
         
             
                  end
         
     | 
| 
       104 
110 
     | 
    
         | 
| 
       105 
111 
     | 
    
         
             
                  def remove_element_observers(element)
         
     | 
| 
       106 
     | 
    
         
            -
                    property_observer_list.each do |observer|
         
     | 
| 
      
 112 
     | 
    
         
            +
                    property_observer_list.each do |observer, options|
         
     | 
| 
       107 
113 
     | 
    
         
             
                      remove_element_observer(element, observer)
         
     | 
| 
       108 
114 
     | 
    
         
             
                    end
         
     | 
| 
       109 
115 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -114,15 +120,15 @@ module Glimmer 
     | 
|
| 
       114 
120 
     | 
    
         
             
                    end
         
     | 
| 
       115 
121 
     | 
    
         
             
                    if element.is_a?(ObservableArray)
         
     | 
| 
       116 
122 
     | 
    
         
             
                      array_object_observer_for(element).unobserve(element)
         
     | 
| 
       117 
     | 
    
         
            -
                      element.property_observer_list.select {| 
     | 
| 
       118 
     | 
    
         
            -
                        o.deregister_all_observables
         
     | 
| 
      
 123 
     | 
    
         
            +
                      element.property_observer_list.select {|obs, opt| obs.respond_to?(:observable_array) && obs.observable_array == self}.each do |o|
         
     | 
| 
      
 124 
     | 
    
         
            +
                        o.deregister_all_observables if o.respond_to?(:deregister_all_observables)
         
     | 
| 
       119 
125 
     | 
    
         
             
                        @array_object_observers.reject! {|k, v| v == o}
         
     | 
| 
       120 
126 
     | 
    
         
             
                      end
         
     | 
| 
       121 
127 
     | 
    
         
             
                    end
         
     | 
| 
       122 
128 
     | 
    
         
             
                  end
         
     | 
| 
       123 
129 
     | 
    
         | 
| 
       124 
130 
     | 
    
         
             
                  def has_observer?(observer)
         
     | 
| 
       125 
     | 
    
         
            -
                    property_observer_list.include?(observer)
         
     | 
| 
      
 131 
     | 
    
         
            +
                    property_observer_list.keys.include?(observer)
         
     | 
| 
       126 
132 
     | 
    
         
             
                  end
         
     | 
| 
       127 
133 
     | 
    
         | 
| 
       128 
134 
     | 
    
         
             
                  def has_observer_element_properties?(observer, element_properties)
         
     | 
| 
         @@ -130,7 +136,7 @@ module Glimmer 
     | 
|
| 
       130 
136 
     | 
    
         
             
                  end
         
     | 
| 
       131 
137 
     | 
    
         | 
| 
       132 
138 
     | 
    
         
             
                  def property_observer_list
         
     | 
| 
       133 
     | 
    
         
            -
                    @property_observer_list ||= Concurrent:: 
     | 
| 
      
 139 
     | 
    
         
            +
                    @property_observer_list ||= Concurrent::Hash.new
         
     | 
| 
       134 
140 
     | 
    
         
             
                  end
         
     | 
| 
       135 
141 
     | 
    
         | 
| 
       136 
142 
     | 
    
         
             
                  def observer_element_properties
         
     | 
| 
         @@ -142,7 +148,7 @@ module Glimmer 
     | 
|
| 
       142 
148 
     | 
    
         
             
                  end
         
     | 
| 
       143 
149 
     | 
    
         | 
| 
       144 
150 
     | 
    
         
             
                  def notify_observers
         
     | 
| 
       145 
     | 
    
         
            -
                    property_observer_list.to_a.each { | 
     | 
| 
      
 151 
     | 
    
         
            +
                    property_observer_list.to_a.each { |obs, opt| obs.call(self) }
         
     | 
| 
       146 
152 
     | 
    
         
             
                  end
         
     | 
| 
       147 
153 
     | 
    
         | 
| 
       148 
154 
     | 
    
         
             
                  def <<(element)
         
     | 
| 
         @@ -366,7 +372,7 @@ module Glimmer 
     | 
|
| 
       366 
372 
     | 
    
         | 
| 
       367 
373 
     | 
    
         
             
                  def unregister_dependent_observers(old_value)
         
     | 
| 
       368 
374 
     | 
    
         
             
                    return unless old_value.is_a?(ObservableModel) || old_value.is_a?(ObservableArray)
         
     | 
| 
       369 
     | 
    
         
            -
                    property_observer_list.each { |observer| observer.unregister_dependents_with_observable(observer.registration_for(self), old_value) }
         
     | 
| 
      
 375 
     | 
    
         
            +
                    property_observer_list.each { |observer, options| observer.unregister_dependents_with_observable(observer.registration_for(self), old_value) }
         
     | 
| 
       370 
376 
     | 
    
         
             
                  end
         
     | 
| 
       371 
377 
     | 
    
         
             
                  alias deregister_dependent_observers unregister_dependent_observers
         
     | 
| 
       372 
378 
     | 
    
         
             
                end
         
     | 
| 
         @@ -19,13 +19,13 @@ 
     | 
|
| 
       19 
19 
     | 
    
         
             
            # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
         
     | 
| 
       20 
20 
     | 
    
         
             
            # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
         
     | 
| 
       21 
21 
     | 
    
         | 
| 
       22 
     | 
    
         
            -
            require 'glimmer/data_binding/ 
     | 
| 
      
 22 
     | 
    
         
            +
            require 'glimmer/data_binding/observable_hashable'
         
     | 
| 
       23 
23 
     | 
    
         
             
            require 'glimmer/data_binding/observer'
         
     | 
| 
       24 
24 
     | 
    
         | 
| 
       25 
25 
     | 
    
         
             
            module Glimmer
         
     | 
| 
       26 
26 
     | 
    
         
             
              module DataBinding
         
     | 
| 
       27 
27 
     | 
    
         
             
                module ObservableHash
         
     | 
| 
       28 
     | 
    
         
            -
                  include  
     | 
| 
      
 28 
     | 
    
         
            +
                  include ObservableHashable
         
     | 
| 
       29 
29 
     | 
    
         | 
| 
       30 
30 
     | 
    
         
             
                  class Notifier
         
     | 
| 
       31 
31 
     | 
    
         
             
                    include Observer
         
     | 
| 
         @@ -40,28 +40,6 @@ module Glimmer 
     | 
|
| 
       40 
40 
     | 
    
         
             
                    end
         
     | 
| 
       41 
41 
     | 
    
         
             
                  end
         
     | 
| 
       42 
42 
     | 
    
         | 
| 
       43 
     | 
    
         
            -
                  OBSERVED_STORE_METHOD = lambda do |key, value|
         
     | 
| 
       44 
     | 
    
         
            -
                    if key_observer_list(key).empty?
         
     | 
| 
       45 
     | 
    
         
            -
                      if all_key_observer_list.empty?
         
     | 
| 
       46 
     | 
    
         
            -
                        self.send('__original__store', key, value)
         
     | 
| 
       47 
     | 
    
         
            -
                      else
         
     | 
| 
       48 
     | 
    
         
            -
                        old_value = self[key]
         
     | 
| 
       49 
     | 
    
         
            -
                        unregister_dependent_observers(nil, old_value) # remove dependent observers previously installed in ensure_array_object_observer and ensure_hash_object_observer
         
     | 
| 
       50 
     | 
    
         
            -
                        self.send('__original__store', key, value)
         
     | 
| 
       51 
     | 
    
         
            -
                        notify_observers(key)
         
     | 
| 
       52 
     | 
    
         
            -
                        ensure_array_object_observer(nil, value, old_value)
         
     | 
| 
       53 
     | 
    
         
            -
                        ensure_hash_object_observer(nil, value, old_value)
         
     | 
| 
       54 
     | 
    
         
            -
                      end
         
     | 
| 
       55 
     | 
    
         
            -
                    else
         
     | 
| 
       56 
     | 
    
         
            -
                      old_value = self[key]
         
     | 
| 
       57 
     | 
    
         
            -
                      unregister_dependent_observers(key, old_value) # remove dependent observers previously installed in ensure_array_object_observer and ensure_hash_object_observer
         
     | 
| 
       58 
     | 
    
         
            -
                      self.send('__original__store', key, value)
         
     | 
| 
       59 
     | 
    
         
            -
                      notify_observers(key)
         
     | 
| 
       60 
     | 
    
         
            -
                      ensure_array_object_observer(key, value, old_value)
         
     | 
| 
       61 
     | 
    
         
            -
                      ensure_hash_object_observer(key, value, old_value)
         
     | 
| 
       62 
     | 
    
         
            -
                    end
         
     | 
| 
       63 
     | 
    
         
            -
                  end
         
     | 
| 
       64 
     | 
    
         
            -
             
     | 
| 
       65 
43 
     | 
    
         
             
                  def add_observer(observer, key = nil, options = {})
         
     | 
| 
       66 
44 
     | 
    
         
             
                    if key.is_a?(Hash)
         
     | 
| 
       67 
45 
     | 
    
         
             
                      options = key
         
     | 
| 
         @@ -106,7 +84,7 @@ module Glimmer 
     | 
|
| 
       106 
84 
     | 
    
         
             
                  end
         
     | 
| 
       107 
85 
     | 
    
         | 
| 
       108 
86 
     | 
    
         
             
                  def key_observer_hash
         
     | 
| 
       109 
     | 
    
         
            -
                    @key_observers ||= Hash.new
         
     | 
| 
      
 87 
     | 
    
         
            +
                    @key_observers ||= Concurrent::Hash.new
         
     | 
| 
       110 
88 
     | 
    
         
             
                  end
         
     | 
| 
       111 
89 
     | 
    
         | 
| 
       112 
90 
     | 
    
         
             
                  def key_observer_list(key)
         
     | 
| 
         @@ -123,24 +101,6 @@ module Glimmer 
     | 
|
| 
       123 
101 
     | 
    
         
             
                    (key_observer_list(key).to_a - all_key_observer_list.to_a).each { |observer| observer.call(self[key], key) }
         
     | 
| 
       124 
102 
     | 
    
         
             
                  end
         
     | 
| 
       125 
103 
     | 
    
         | 
| 
       126 
     | 
    
         
            -
                  def add_key_writer_observer(key = nil, options)
         
     | 
| 
       127 
     | 
    
         
            -
                    ensure_array_object_observer(key, self[key], nil, options)
         
     | 
| 
       128 
     | 
    
         
            -
                    ensure_hash_object_observer(key, self[key], nil, options)
         
     | 
| 
       129 
     | 
    
         
            -
                    begin
         
     | 
| 
       130 
     | 
    
         
            -
                      method('__original__store')
         
     | 
| 
       131 
     | 
    
         
            -
                    rescue
         
     | 
| 
       132 
     | 
    
         
            -
                      define_singleton_method('__original__store', store_method)
         
     | 
| 
       133 
     | 
    
         
            -
                      define_singleton_method('[]=', &OBSERVED_STORE_METHOD)
         
     | 
| 
       134 
     | 
    
         
            -
                    end
         
     | 
| 
       135 
     | 
    
         
            -
                  rescue => e
         
     | 
| 
       136 
     | 
    
         
            -
                    #ignore writing if no key writer exists
         
     | 
| 
       137 
     | 
    
         
            -
                    Glimmer::Config.logger.debug {"No need to observe store method: '[]='\n#{e.message}\n#{e.backtrace.join("\n")}"}
         
     | 
| 
       138 
     | 
    
         
            -
                  end
         
     | 
| 
       139 
     | 
    
         
            -
                  
         
     | 
| 
       140 
     | 
    
         
            -
                  def store_method
         
     | 
| 
       141 
     | 
    
         
            -
                    self.class.instance_method('[]=') rescue self.method('[]=')
         
     | 
| 
       142 
     | 
    
         
            -
                  end
         
     | 
| 
       143 
     | 
    
         
            -
             
     | 
| 
       144 
104 
     | 
    
         
             
                  def unregister_dependent_observers(key, old_value)
         
     | 
| 
       145 
105 
     | 
    
         
             
                    # TODO look into optimizing this
         
     | 
| 
       146 
106 
     | 
    
         
             
                    return unless old_value.is_a?(ObservableModel) || old_value.is_a?(ObservableArray) || old_value.is_a?(ObservableHash)
         
     | 
| 
         @@ -166,24 +126,6 @@ module Glimmer 
     | 
|
| 
       166 
126 
     | 
    
         
             
                    @array_object_observers[key]
         
     | 
| 
       167 
127 
     | 
    
         
             
                  end
         
     | 
| 
       168 
128 
     | 
    
         | 
| 
       169 
     | 
    
         
            -
                  def ensure_hash_object_observer(key, object, old_object = nil, options = {})
         
     | 
| 
       170 
     | 
    
         
            -
                    options ||= {}
         
     | 
| 
       171 
     | 
    
         
            -
                    return unless object&.is_a?(Hash)
         
     | 
| 
       172 
     | 
    
         
            -
                    hash_object_observer = hash_object_observer_for(key)
         
     | 
| 
       173 
     | 
    
         
            -
                    hash_observer_registration = hash_object_observer.observe(object, options)
         
     | 
| 
       174 
     | 
    
         
            -
                    key_observer_list(key).each do |observer|
         
     | 
| 
       175 
     | 
    
         
            -
                      my_registration = observer.registration_for(self, key) # TODO eliminate repetition
         
     | 
| 
       176 
     | 
    
         
            -
                      observer.add_dependent(my_registration => hash_observer_registration)
         
     | 
| 
       177 
     | 
    
         
            -
                    end
         
     | 
| 
       178 
     | 
    
         
            -
                    hash_object_observer_for(key).unregister(old_object) if old_object.is_a?(ObservableHash)
         
     | 
| 
       179 
     | 
    
         
            -
                  end
         
     | 
| 
       180 
     | 
    
         
            -
             
     | 
| 
       181 
     | 
    
         
            -
                  def hash_object_observer_for(key)
         
     | 
| 
       182 
     | 
    
         
            -
                    @hash_object_observers ||= Concurrent::Hash.new
         
     | 
| 
       183 
     | 
    
         
            -
                    @hash_object_observers[key] = ObservableModel::Notifier.new(self, key) unless @hash_object_observers.has_key?(key)
         
     | 
| 
       184 
     | 
    
         
            -
                    @hash_object_observers[key]
         
     | 
| 
       185 
     | 
    
         
            -
                  end
         
     | 
| 
       186 
     | 
    
         
            -
                  
         
     | 
| 
       187 
129 
     | 
    
         
             
                  def delete(key, &block)
         
     | 
| 
       188 
130 
     | 
    
         
             
                    old_value = self[key]
         
     | 
| 
       189 
131 
     | 
    
         
             
                    unless old_value.nil?
         
     | 
| 
         @@ -0,0 +1,75 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Copyright (c) 2007-2021 Andy Maleh
         
     | 
| 
      
 2 
     | 
    
         
            +
            #
         
     | 
| 
      
 3 
     | 
    
         
            +
            # Permission is hereby granted, free of charge, to any person obtaining
         
     | 
| 
      
 4 
     | 
    
         
            +
            # a copy of this software and associated documentation files (the
         
     | 
| 
      
 5 
     | 
    
         
            +
            # "Software"), to deal in the Software without restriction, including
         
     | 
| 
      
 6 
     | 
    
         
            +
            # without limitation the rights to use, copy, modify, merge, publish,
         
     | 
| 
      
 7 
     | 
    
         
            +
            # distribute, sublicense, and/or sell copies of the Software, and to
         
     | 
| 
      
 8 
     | 
    
         
            +
            # permit persons to whom the Software is furnished to do so, subject to
         
     | 
| 
      
 9 
     | 
    
         
            +
            # the following conditions:
         
     | 
| 
      
 10 
     | 
    
         
            +
            #
         
     | 
| 
      
 11 
     | 
    
         
            +
            # The above copyright notice and this permission notice shall be
         
     | 
| 
      
 12 
     | 
    
         
            +
            # included in all copies or substantial portions of the Software.
         
     | 
| 
      
 13 
     | 
    
         
            +
            #
         
     | 
| 
      
 14 
     | 
    
         
            +
            # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
         
     | 
| 
      
 15 
     | 
    
         
            +
            # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
         
     | 
| 
      
 16 
     | 
    
         
            +
            # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
         
     | 
| 
      
 17 
     | 
    
         
            +
            # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
         
     | 
| 
      
 18 
     | 
    
         
            +
            # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
         
     | 
| 
      
 19 
     | 
    
         
            +
            # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
         
     | 
| 
      
 20 
     | 
    
         
            +
            # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            require 'glimmer/data_binding/observable'
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            module Glimmer
         
     | 
| 
      
 25 
     | 
    
         
            +
              module DataBinding
         
     | 
| 
      
 26 
     | 
    
         
            +
                # Represents a Hash-like object with attributes writable via :[]= store method like Hash, Struct, and OpenStruct
         
     | 
| 
      
 27 
     | 
    
         
            +
                # Expects including class to have the following methods:
         
     | 
| 
      
 28 
     | 
    
         
            +
                # - key_observer_list
         
     | 
| 
      
 29 
     | 
    
         
            +
                # - all_key_observer_list
         
     | 
| 
      
 30 
     | 
    
         
            +
                # - unregister_dependent_observer
         
     | 
| 
      
 31 
     | 
    
         
            +
                # - ensure_array_object_observer
         
     | 
| 
      
 32 
     | 
    
         
            +
                module ObservableHashable
         
     | 
| 
      
 33 
     | 
    
         
            +
                  include Observable
         
     | 
| 
      
 34 
     | 
    
         
            +
                  
         
     | 
| 
      
 35 
     | 
    
         
            +
                  OBSERVED_STORE_METHOD = lambda do |options|
         
     | 
| 
      
 36 
     | 
    
         
            +
                    lambda do |key, value|
         
     | 
| 
      
 37 
     | 
    
         
            +
                      if key_observer_list(key).empty?
         
     | 
| 
      
 38 
     | 
    
         
            +
                        if all_key_observer_list.empty?
         
     | 
| 
      
 39 
     | 
    
         
            +
                          self.send('__original__store', key, value)
         
     | 
| 
      
 40 
     | 
    
         
            +
                        else
         
     | 
| 
      
 41 
     | 
    
         
            +
                          old_value = self[key]
         
     | 
| 
      
 42 
     | 
    
         
            +
                          unregister_dependent_observers(nil, old_value) # remove dependent observers previously installed in ensure_array_object_observer
         
     | 
| 
      
 43 
     | 
    
         
            +
                          self.send('__original__store', key, value)
         
     | 
| 
      
 44 
     | 
    
         
            +
                          notify_observers(key)
         
     | 
| 
      
 45 
     | 
    
         
            +
                          ensure_array_object_observer(nil, value, old_value, options)
         
     | 
| 
      
 46 
     | 
    
         
            +
                        end
         
     | 
| 
      
 47 
     | 
    
         
            +
                      else
         
     | 
| 
      
 48 
     | 
    
         
            +
                        old_value = self[key]
         
     | 
| 
      
 49 
     | 
    
         
            +
                        unregister_dependent_observers(key, old_value) # remove dependent observers previously installed in ensure_array_object_observer
         
     | 
| 
      
 50 
     | 
    
         
            +
                        self.send('__original__store', key, value)
         
     | 
| 
      
 51 
     | 
    
         
            +
                        notify_observers(key)
         
     | 
| 
      
 52 
     | 
    
         
            +
                        ensure_array_object_observer(key, value, old_value, options)
         
     | 
| 
      
 53 
     | 
    
         
            +
                      end
         
     | 
| 
      
 54 
     | 
    
         
            +
                    end
         
     | 
| 
      
 55 
     | 
    
         
            +
                  end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                  def add_key_writer_observer(key = nil, options)
         
     | 
| 
      
 58 
     | 
    
         
            +
                    ensure_array_object_observer(key, self[key], nil, options)
         
     | 
| 
      
 59 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 60 
     | 
    
         
            +
                      method('__original__store')
         
     | 
| 
      
 61 
     | 
    
         
            +
                    rescue
         
     | 
| 
      
 62 
     | 
    
         
            +
                      define_singleton_method('__original__store', store_method)
         
     | 
| 
      
 63 
     | 
    
         
            +
                      define_singleton_method('[]=', &OBSERVED_STORE_METHOD.call(options))
         
     | 
| 
      
 64 
     | 
    
         
            +
                    end
         
     | 
| 
      
 65 
     | 
    
         
            +
                  rescue => e
         
     | 
| 
      
 66 
     | 
    
         
            +
                    #ignore writing if no key writer exists
         
     | 
| 
      
 67 
     | 
    
         
            +
                    Glimmer::Config.logger.debug {"No need to observe store method: '[]='\n#{e.message}\n#{e.backtrace.join("\n")}"}
         
     | 
| 
      
 68 
     | 
    
         
            +
                  end
         
     | 
| 
      
 69 
     | 
    
         
            +
                  
         
     | 
| 
      
 70 
     | 
    
         
            +
                  def store_method
         
     | 
| 
      
 71 
     | 
    
         
            +
                    self.class.instance_method('[]=') rescue self.method('[]=')
         
     | 
| 
      
 72 
     | 
    
         
            +
                  end
         
     | 
| 
      
 73 
     | 
    
         
            +
                end
         
     | 
| 
      
 74 
     | 
    
         
            +
              end
         
     | 
| 
      
 75 
     | 
    
         
            +
            end
         
     |