glimmer 1.0.3 → 1.0.8
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/LICENSE.txt +1 -1
- data/PROCESS.md +2 -2
- data/README.md +387 -224
- data/VERSION +1 -1
- data/glimmer.gemspec +8 -7
- data/lib/glimmer.rb +6 -5
- data/lib/glimmer/config.rb +6 -6
- data/lib/glimmer/data_binding/model_binding.rb +7 -7
- data/lib/glimmer/data_binding/observable.rb +4 -4
- data/lib/glimmer/data_binding/observable_array.rb +6 -6
- data/lib/glimmer/data_binding/observable_model.rb +27 -8
- data/lib/glimmer/data_binding/observer.rb +10 -8
- data/lib/glimmer/dsl/engine.rb +23 -22
- data/lib/glimmer/dsl/expression.rb +5 -5
- data/lib/glimmer/dsl/expression_handler.rb +4 -4
- data/lib/glimmer/dsl/parent_expression.rb +4 -4
- data/lib/glimmer/dsl/static_expression.rb +6 -6
- data/lib/glimmer/dsl/top_level_expression.rb +4 -4
- data/lib/glimmer/error.rb +4 -4
- data/lib/glimmer/invalid_keyword_error.rb +4 -4
- metadata +30 -11
    
        data/VERSION
    CHANGED
    
    | @@ -1 +1 @@ | |
| 1 | 
            -
            1.0. | 
| 1 | 
            +
            1.0.8
         | 
    
        data/glimmer.gemspec
    CHANGED
    
    | @@ -2,20 +2,19 @@ | |
| 2 2 | 
             
            # DO NOT EDIT THIS FILE DIRECTLY
         | 
| 3 3 | 
             
            # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
         | 
| 4 4 | 
             
            # -*- encoding: utf-8 -*-
         | 
| 5 | 
            -
            # stub: glimmer 1.0. | 
| 5 | 
            +
            # stub: glimmer 1.0.8 ruby lib
         | 
| 6 6 |  | 
| 7 7 | 
             
            Gem::Specification.new do |s|
         | 
| 8 8 | 
             
              s.name = "glimmer".freeze
         | 
| 9 | 
            -
              s.version = "1.0. | 
| 9 | 
            +
              s.version = "1.0.8"
         | 
| 10 10 |  | 
| 11 11 | 
             
              s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
         | 
| 12 12 | 
             
              s.require_paths = ["lib".freeze]
         | 
| 13 13 | 
             
              s.authors = ["AndyMaleh".freeze]
         | 
| 14 | 
            -
              s.date = " | 
| 15 | 
            -
              s.description = "Glimmer is a Ruby DSL Framework consisting of a DSL Engine and Observable/Observer/Data-Binding Library. Used in the Glimmer DSL for SWT (JRuby Desktop Development GUI  | 
| 14 | 
            +
              s.date = "2021-01-19"
         | 
| 15 | 
            +
              s.description = "Glimmer is a Ruby DSL Framework consisting of a DSL Engine and an Observable/Observer/Data-Binding Library. Used in the Glimmer DSL for SWT (JRuby Desktop Development GUI Framework), the Glimmer DSL for Tk (Ruby Desktop Development GUI Library), the Glimmer DSL for Opal (Pure Ruby Web GUI and Auto-Webifier of Desktop Apps), the Glimmer DSL for XML (& HTML), and the Glimmer DSL for CSS.".freeze
         | 
| 16 16 | 
             
              s.email = "andy.am@gmail.com".freeze
         | 
| 17 17 | 
             
              s.extra_rdoc_files = [
         | 
| 18 | 
            -
                "CHANGELOG.md",
         | 
| 19 18 | 
             
                "LICENSE.txt",
         | 
| 20 19 | 
             
                "README.md"
         | 
| 21 20 | 
             
              ]
         | 
| @@ -55,26 +54,28 @@ Gem::Specification.new do |s| | |
| 55 54 | 
             
              if s.respond_to? :add_runtime_dependency then
         | 
| 56 55 | 
             
                s.add_runtime_dependency(%q<array_include_methods>.freeze, [">= 1.0.4", "< 2.0.0"])
         | 
| 57 56 | 
             
                s.add_runtime_dependency(%q<facets>.freeze, [">= 3.1.0", "< 4.0.0"])
         | 
| 57 | 
            +
                s.add_runtime_dependency(%q<concurrent-ruby>.freeze, [">= 1.1.7", "< 2.0.0"])
         | 
| 58 58 | 
             
                s.add_development_dependency(%q<rspec-mocks>.freeze, ["~> 3.5.0"])
         | 
| 59 59 | 
             
                s.add_development_dependency(%q<rspec>.freeze, ["~> 3.5.0"])
         | 
| 60 60 | 
             
                s.add_development_dependency(%q<puts_debuggerer>.freeze, ["~> 0.10.0"])
         | 
| 61 61 | 
             
                s.add_development_dependency(%q<rake>.freeze, [">= 10.1.0", "< 14.0.0"])
         | 
| 62 62 | 
             
                s.add_development_dependency(%q<jeweler>.freeze, [">= 2.0.0", "< 3.0.0"])
         | 
| 63 63 | 
             
                s.add_development_dependency(%q<rdoc>.freeze, [">= 6.2.1", "< 7.0.0"])
         | 
| 64 | 
            -
                s.add_development_dependency(%q<coveralls>.freeze, [" | 
| 64 | 
            +
                s.add_development_dependency(%q<coveralls>.freeze, [">= 0"])
         | 
| 65 65 | 
             
                s.add_development_dependency(%q<simplecov>.freeze, ["~> 0.16.1"])
         | 
| 66 66 | 
             
                s.add_development_dependency(%q<simplecov-lcov>.freeze, ["~> 0.7.0"])
         | 
| 67 67 | 
             
                s.add_development_dependency(%q<rake-tui>.freeze, [">= 0"])
         | 
| 68 68 | 
             
              else
         | 
| 69 69 | 
             
                s.add_dependency(%q<array_include_methods>.freeze, [">= 1.0.4", "< 2.0.0"])
         | 
| 70 70 | 
             
                s.add_dependency(%q<facets>.freeze, [">= 3.1.0", "< 4.0.0"])
         | 
| 71 | 
            +
                s.add_dependency(%q<concurrent-ruby>.freeze, [">= 1.1.7", "< 2.0.0"])
         | 
| 71 72 | 
             
                s.add_dependency(%q<rspec-mocks>.freeze, ["~> 3.5.0"])
         | 
| 72 73 | 
             
                s.add_dependency(%q<rspec>.freeze, ["~> 3.5.0"])
         | 
| 73 74 | 
             
                s.add_dependency(%q<puts_debuggerer>.freeze, ["~> 0.10.0"])
         | 
| 74 75 | 
             
                s.add_dependency(%q<rake>.freeze, [">= 10.1.0", "< 14.0.0"])
         | 
| 75 76 | 
             
                s.add_dependency(%q<jeweler>.freeze, [">= 2.0.0", "< 3.0.0"])
         | 
| 76 77 | 
             
                s.add_dependency(%q<rdoc>.freeze, [">= 6.2.1", "< 7.0.0"])
         | 
| 77 | 
            -
                s.add_dependency(%q<coveralls>.freeze, [" | 
| 78 | 
            +
                s.add_dependency(%q<coveralls>.freeze, [">= 0"])
         | 
| 78 79 | 
             
                s.add_dependency(%q<simplecov>.freeze, ["~> 0.16.1"])
         | 
| 79 80 | 
             
                s.add_dependency(%q<simplecov-lcov>.freeze, ["~> 0.7.0"])
         | 
| 80 81 | 
             
                s.add_dependency(%q<rake-tui>.freeze, [">= 0"])
         | 
    
        data/lib/glimmer.rb
    CHANGED
    
    | @@ -1,5 +1,5 @@ | |
| 1 | 
            -
            # Copyright (c) 2007- | 
| 2 | 
            -
            # | 
| 1 | 
            +
            # Copyright (c) 2007-2021 Andy Maleh
         | 
| 2 | 
            +
            #
         | 
| 3 3 | 
             
            # Permission is hereby granted, free of charge, to any person obtaining
         | 
| 4 4 | 
             
            # a copy of this software and associated documentation files (the
         | 
| 5 5 | 
             
            # "Software"), to deal in the Software without restriction, including
         | 
| @@ -7,10 +7,10 @@ | |
| 7 7 | 
             
            # distribute, sublicense, and/or sell copies of the Software, and to
         | 
| 8 8 | 
             
            # permit persons to whom the Software is furnished to do so, subject to
         | 
| 9 9 | 
             
            # the following conditions:
         | 
| 10 | 
            -
            # | 
| 10 | 
            +
            #
         | 
| 11 11 | 
             
            # The above copyright notice and this permission notice shall be
         | 
| 12 12 | 
             
            # included in all copies or substantial portions of the Software.
         | 
| 13 | 
            -
            # | 
| 13 | 
            +
            #
         | 
| 14 14 | 
             
            # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
         | 
| 15 15 | 
             
            # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
         | 
| 16 16 | 
             
            # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
         | 
| @@ -22,6 +22,7 @@ | |
| 22 22 | 
             
            require 'logger'
         | 
| 23 23 | 
             
            require 'set'
         | 
| 24 24 | 
             
            require 'array_include_methods'
         | 
| 25 | 
            +
            require 'concurrent-ruby'
         | 
| 25 26 |  | 
| 26 27 | 
             
            $LOAD_PATH.unshift(File.expand_path('..', __FILE__))
         | 
| 27 28 |  | 
| @@ -70,7 +71,7 @@ module Glimmer | |
| 70 71 | 
             
                  end
         | 
| 71 72 | 
             
                  Glimmer.loop_last_data = new_loop_data
         | 
| 72 73 | 
             
                  Glimmer::Config.logger.info {"Interpreting keyword: #{method_symbol}"}
         | 
| 73 | 
            -
                  Glimmer::DSL::Engine.interpret(method_symbol, *args, &block) | 
| 74 | 
            +
                  Glimmer::DSL::Engine.interpret(method_symbol, *args, &block)
         | 
| 74 75 | 
             
                end
         | 
| 75 76 | 
             
              rescue InvalidKeywordError => e
         | 
| 76 77 | 
             
                Glimmer::Config.logger.error {"Encountered an invalid keyword at this object: #{self}"}
         | 
    
        data/lib/glimmer/config.rb
    CHANGED
    
    | @@ -1,5 +1,5 @@ | |
| 1 | 
            -
            # Copyright (c) 2007- | 
| 2 | 
            -
            # | 
| 1 | 
            +
            # Copyright (c) 2007-2021 Andy Maleh
         | 
| 2 | 
            +
            #
         | 
| 3 3 | 
             
            # Permission is hereby granted, free of charge, to any person obtaining
         | 
| 4 4 | 
             
            # a copy of this software and associated documentation files (the
         | 
| 5 5 | 
             
            # "Software"), to deal in the Software without restriction, including
         | 
| @@ -7,10 +7,10 @@ | |
| 7 7 | 
             
            # distribute, sublicense, and/or sell copies of the Software, and to
         | 
| 8 8 | 
             
            # permit persons to whom the Software is furnished to do so, subject to
         | 
| 9 9 | 
             
            # the following conditions:
         | 
| 10 | 
            -
            # | 
| 10 | 
            +
            #
         | 
| 11 11 | 
             
            # The above copyright notice and this permission notice shall be
         | 
| 12 12 | 
             
            # included in all copies or substantial portions of the Software.
         | 
| 13 | 
            -
            # | 
| 13 | 
            +
            #
         | 
| 14 14 | 
             
            # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
         | 
| 15 15 | 
             
            # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
         | 
| 16 16 | 
             
            # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
         | 
| @@ -46,7 +46,7 @@ module Glimmer | |
| 46 46 | 
             
                  end
         | 
| 47 47 |  | 
| 48 48 | 
             
                  # Returns Glimmer logger (standard Ruby logger)
         | 
| 49 | 
            -
                  def logger | 
| 49 | 
            +
                  def logger
         | 
| 50 50 | 
             
                    reset_logger! unless defined? @@logger
         | 
| 51 51 | 
             
                    @@logger
         | 
| 52 52 | 
             
                  end
         | 
| @@ -56,7 +56,7 @@ module Glimmer | |
| 56 56 | 
             
                  end
         | 
| 57 57 |  | 
| 58 58 | 
             
                  def reset_logger!
         | 
| 59 | 
            -
                    self.logger = Logger.new(STDOUT).tap do |logger| | 
| 59 | 
            +
                    self.logger = Logger.new(STDOUT).tap do |logger|
         | 
| 60 60 | 
             
                      logger.level = Logger::ERROR
         | 
| 61 61 | 
             
                      begin
         | 
| 62 62 | 
             
                        logger.level = ENV['GLIMMER_LOGGER_LEVEL'].strip.downcase if ENV['GLIMMER_LOGGER_LEVEL']
         | 
| @@ -1,4 +1,4 @@ | |
| 1 | 
            -
            # Copyright (c) 2007- | 
| 1 | 
            +
            # Copyright (c) 2007-2021 Andy Maleh
         | 
| 2 2 | 
             
            #
         | 
| 3 3 | 
             
            # Permission is hereby granted, free of charge, to any person obtaining
         | 
| 4 4 | 
             
            # a copy of this software and associated documentation files (the
         | 
| @@ -33,7 +33,7 @@ module Glimmer | |
| 33 33 | 
             
                  def initialize(base_model, property_name_expression, binding_options = nil)
         | 
| 34 34 | 
             
                    @base_model = base_model
         | 
| 35 35 | 
             
                    @property_name_expression = property_name_expression
         | 
| 36 | 
            -
                    @binding_options = binding_options ||  | 
| 36 | 
            +
                    @binding_options = binding_options || Concurrent::Hash.new
         | 
| 37 37 | 
             
                    if computed?
         | 
| 38 38 | 
             
                      @computed_model_bindings = computed_by.map do |computed_by_property_expression|
         | 
| 39 39 | 
             
                        self.class.new(base_model, computed_by_property_expression)
         | 
| @@ -120,9 +120,9 @@ module Glimmer | |
| 120 120 | 
             
                  end
         | 
| 121 121 |  | 
| 122 122 | 
             
                  def nested_property_observers_for(observer)
         | 
| 123 | 
            -
                    @nested_property_observers_collection ||=  | 
| 123 | 
            +
                    @nested_property_observers_collection ||= Concurrent::Hash.new
         | 
| 124 124 | 
             
                    unless @nested_property_observers_collection.has_key?(observer)
         | 
| 125 | 
            -
                      @nested_property_observers_collection[observer] = nested_property_names.reduce( | 
| 125 | 
            +
                      @nested_property_observers_collection[observer] = nested_property_names.reduce(Concurrent::Hash.new) do |output, property_name|
         | 
| 126 126 | 
             
                        output.merge(
         | 
| 127 127 | 
             
                          property_name => Observer.proc do |new_value|
         | 
| 128 128 | 
             
                            # Ensure reattaching observers when a higher level nested property is updated (e.g. person.address changes reattaches person.address.street observer)
         | 
| @@ -164,7 +164,7 @@ module Glimmer | |
| 164 164 | 
             
                  end
         | 
| 165 165 |  | 
| 166 166 | 
             
                  def computed_observer_for(observer)
         | 
| 167 | 
            -
                    @computed_observer_collection ||=  | 
| 167 | 
            +
                    @computed_observer_collection ||= Concurrent::Hash.new
         | 
| 168 168 | 
             
                    unless @computed_observer_collection.has_key?(observer)
         | 
| 169 169 | 
             
                      @computed_observer_collection[observer] = Observer.proc do |new_value|
         | 
| 170 170 | 
             
                        observer.call(evaluate_property)
         | 
| @@ -209,7 +209,7 @@ module Glimmer | |
| 209 209 | 
             
                  def call(value)
         | 
| 210 210 | 
             
                    return if model.nil?
         | 
| 211 211 | 
             
                    converted_value = value
         | 
| 212 | 
            -
                    invoke_property_writer(model, "#{property_name}=", converted_value) unless  | 
| 212 | 
            +
                    invoke_property_writer(model, "#{property_name}=", converted_value) unless converted_value == evaluate_property
         | 
| 213 213 | 
             
                  end
         | 
| 214 214 |  | 
| 215 215 | 
             
                  def evaluate_property
         | 
| @@ -242,7 +242,7 @@ module Glimmer | |
| 242 242 | 
             
                  end
         | 
| 243 243 |  | 
| 244 244 | 
             
                  def invoke_property_writer(object, property_expression, value)
         | 
| 245 | 
            -
                     | 
| 245 | 
            +
                    raise "Cannot invoke `#{property_expression}` because ModelBinding#binding_options[:read_only]=true" if @binding_options[:read_only]
         | 
| 246 246 | 
             
                    value = convert_on_write(value)
         | 
| 247 247 | 
             
                    if property_indexed?(property_expression)
         | 
| 248 248 | 
             
                      property_method = '[]='
         | 
| @@ -1,5 +1,5 @@ | |
| 1 | 
            -
            # Copyright (c) 2007- | 
| 2 | 
            -
            # | 
| 1 | 
            +
            # Copyright (c) 2007-2021 Andy Maleh
         | 
| 2 | 
            +
            #
         | 
| 3 3 | 
             
            # Permission is hereby granted, free of charge, to any person obtaining
         | 
| 4 4 | 
             
            # a copy of this software and associated documentation files (the
         | 
| 5 5 | 
             
            # "Software"), to deal in the Software without restriction, including
         | 
| @@ -7,10 +7,10 @@ | |
| 7 7 | 
             
            # distribute, sublicense, and/or sell copies of the Software, and to
         | 
| 8 8 | 
             
            # permit persons to whom the Software is furnished to do so, subject to
         | 
| 9 9 | 
             
            # the following conditions:
         | 
| 10 | 
            -
            # | 
| 10 | 
            +
            #
         | 
| 11 11 | 
             
            # The above copyright notice and this permission notice shall be
         | 
| 12 12 | 
             
            # included in all copies or substantial portions of the Software.
         | 
| 13 | 
            -
            # | 
| 13 | 
            +
            #
         | 
| 14 14 | 
             
            # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
         | 
| 15 15 | 
             
            # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
         | 
| 16 16 | 
             
            # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
         | 
| @@ -1,4 +1,4 @@ | |
| 1 | 
            -
            # Copyright (c) 2007- | 
| 1 | 
            +
            # Copyright (c) 2007-2021 Andy Maleh
         | 
| 2 2 | 
             
            #
         | 
| 3 3 | 
             
            # Permission is hereby granted, free of charge, to any person obtaining
         | 
| 4 4 | 
             
            # a copy of this software and associated documentation files (the
         | 
| @@ -34,7 +34,7 @@ module Glimmer | |
| 34 34 | 
             
                    element_properties = element_properties.flatten.compact.uniq
         | 
| 35 35 | 
             
                    return observer if has_observer?(observer) && has_observer_element_properties?(observer, element_properties)
         | 
| 36 36 | 
             
                    property_observer_list << observer
         | 
| 37 | 
            -
                    observer_element_properties[observer] = element_properties_for(observer) + Set.new(element_properties)
         | 
| 37 | 
            +
                    observer_element_properties[observer] = element_properties_for(observer) + Concurrent::Set.new(element_properties)
         | 
| 38 38 | 
             
                    each { |element| add_element_observer(element, observer) }
         | 
| 39 39 | 
             
                    observer
         | 
| 40 40 | 
             
                  end
         | 
| @@ -55,7 +55,7 @@ module Glimmer | |
| 55 55 | 
             
                    element_properties = element_properties.flatten.compact.uniq
         | 
| 56 56 | 
             
                    if !element_properties.empty?
         | 
| 57 57 | 
             
                      old_element_properties = element_properties_for(observer)
         | 
| 58 | 
            -
                      observer_element_properties[observer] = element_properties_for(observer) - Set.new(element_properties)
         | 
| 58 | 
            +
                      observer_element_properties[observer] = element_properties_for(observer) - Concurrent::Set.new(element_properties)
         | 
| 59 59 | 
             
                      each { |element| element_properties.each { |property| observer.unobserve(element, property) } }
         | 
| 60 60 | 
             
                    end
         | 
| 61 61 | 
             
                    if element_properties_for(observer).empty?
         | 
| @@ -87,15 +87,15 @@ module Glimmer | |
| 87 87 | 
             
                  end
         | 
| 88 88 |  | 
| 89 89 | 
             
                  def property_observer_list
         | 
| 90 | 
            -
                    @property_observer_list ||= Set.new
         | 
| 90 | 
            +
                    @property_observer_list ||= Concurrent::Set.new
         | 
| 91 91 | 
             
                  end
         | 
| 92 92 |  | 
| 93 93 | 
             
                  def observer_element_properties
         | 
| 94 | 
            -
                    @observer_element_properties ||=  | 
| 94 | 
            +
                    @observer_element_properties ||= Concurrent::Hash.new
         | 
| 95 95 | 
             
                  end
         | 
| 96 96 |  | 
| 97 97 | 
             
                  def element_properties_for(observer)
         | 
| 98 | 
            -
                    observer_element_properties[observer] ||= Set.new
         | 
| 98 | 
            +
                    observer_element_properties[observer] ||= Concurrent::Set.new
         | 
| 99 99 | 
             
                  end
         | 
| 100 100 |  | 
| 101 101 | 
             
                  def notify_observers
         | 
| @@ -1,4 +1,4 @@ | |
| 1 | 
            -
            # Copyright (c) 2007- | 
| 1 | 
            +
            # Copyright (c) 2007-2021 Andy Maleh
         | 
| 2 2 | 
             
            #
         | 
| 3 3 | 
             
            # Permission is hereby granted, free of charge, to any person obtaining
         | 
| 4 4 | 
             
            # a copy of this software and associated documentation files (the
         | 
| @@ -43,7 +43,7 @@ module Glimmer | |
| 43 43 | 
             
                    lambda do |value|
         | 
| 44 44 | 
             
                      old_value = self.send(property_name)
         | 
| 45 45 | 
             
                      unregister_dependent_observers(property_name, old_value)
         | 
| 46 | 
            -
                      self.send(" | 
| 46 | 
            +
                      self.send("__original__#{property_writer_name}", value)
         | 
| 47 47 | 
             
                      notify_observers(property_name)
         | 
| 48 48 | 
             
                      ensure_array_object_observer(property_name, value, old_value)
         | 
| 49 49 | 
             
                    end
         | 
| @@ -57,7 +57,26 @@ module Glimmer | |
| 57 57 | 
             
                  end
         | 
| 58 58 |  | 
| 59 59 | 
             
                  def remove_observer(observer, property_name)
         | 
| 60 | 
            -
                     | 
| 60 | 
            +
                    if has_observer?(observer, property_name)
         | 
| 61 | 
            +
                      property_observer_list(property_name).delete(observer)
         | 
| 62 | 
            +
                      observer.unobserve(self, property_name)
         | 
| 63 | 
            +
                    end
         | 
| 64 | 
            +
                  end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                  def remove_observers(property_name)
         | 
| 67 | 
            +
                    property_observer_hash[property_name.to_sym].each do |observer|
         | 
| 68 | 
            +
                      remove_observer(observer, property_name)
         | 
| 69 | 
            +
                    end
         | 
| 70 | 
            +
                    property_observer_hash.delete(property_name.to_sym)
         | 
| 71 | 
            +
                  end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                  def remove_all_observers
         | 
| 74 | 
            +
                    all_observers = property_observer_hash.clone
         | 
| 75 | 
            +
                    property_observer_hash.keys.each do |property_name|
         | 
| 76 | 
            +
                      remove_observers(property_name)
         | 
| 77 | 
            +
                    end
         | 
| 78 | 
            +
                    property_observer_hash.clear
         | 
| 79 | 
            +
                    all_observers
         | 
| 61 80 | 
             
                  end
         | 
| 62 81 |  | 
| 63 82 | 
             
                  def has_observer?(observer, property_name)
         | 
| @@ -73,7 +92,7 @@ module Glimmer | |
| 73 92 | 
             
                  end
         | 
| 74 93 |  | 
| 75 94 | 
             
                  def property_observer_list(property_name)
         | 
| 76 | 
            -
                    property_observer_hash[property_name.to_sym] = Set.new unless property_observer_hash[property_name.to_sym]
         | 
| 95 | 
            +
                    property_observer_hash[property_name.to_sym] = Concurrent::Set.new unless property_observer_hash[property_name.to_sym]
         | 
| 77 96 | 
             
                    property_observer_hash[property_name.to_sym]
         | 
| 78 97 | 
             
                  end
         | 
| 79 98 |  | 
| @@ -86,9 +105,9 @@ module Glimmer | |
| 86 105 | 
             
                    method(property_writer_name)
         | 
| 87 106 | 
             
                    ensure_array_object_observer(property_name, send(property_name))
         | 
| 88 107 | 
             
                    begin
         | 
| 89 | 
            -
                       | 
| 108 | 
            +
                      method("__original__#{property_writer_name}")
         | 
| 90 109 | 
             
                    rescue
         | 
| 91 | 
            -
                      define_singleton_method(" | 
| 110 | 
            +
                      define_singleton_method("__original__#{property_writer_name}", property_writer_method(property_writer_name))
         | 
| 92 111 | 
             
                      define_singleton_method(property_writer_name, &PROPERTY_WRITER_FACTORY.call(property_name))
         | 
| 93 112 | 
             
                    end
         | 
| 94 113 | 
             
                  rescue => e
         | 
| @@ -107,7 +126,7 @@ module Glimmer | |
| 107 126 | 
             
                  end
         | 
| 108 127 |  | 
| 109 128 | 
             
                  def ensure_array_object_observer(property_name, object, old_object = nil)
         | 
| 110 | 
            -
                    return unless object | 
| 129 | 
            +
                    return unless object&.is_a?(Array)
         | 
| 111 130 | 
             
                    array_object_observer = array_object_observer_for(property_name)
         | 
| 112 131 | 
             
                    array_observer_registration = array_object_observer.observe(object)
         | 
| 113 132 | 
             
                    property_observer_list(property_name).each do |observer|
         | 
| @@ -118,7 +137,7 @@ module Glimmer | |
| 118 137 | 
             
                  end
         | 
| 119 138 |  | 
| 120 139 | 
             
                  def array_object_observer_for(property_name)
         | 
| 121 | 
            -
                    @array_object_observers ||=  | 
| 140 | 
            +
                    @array_object_observers ||= Concurrent::Hash.new
         | 
| 122 141 | 
             
                    @array_object_observers[property_name] = ObservableModel::Notifier.new(self, property_name) unless @array_object_observers.has_key?(property_name)
         | 
| 123 142 | 
             
                    @array_object_observers[property_name]
         | 
| 124 143 | 
             
                  end
         | 
| @@ -1,5 +1,5 @@ | |
| 1 | 
            -
            # Copyright (c) 2007- | 
| 2 | 
            -
            # | 
| 1 | 
            +
            # Copyright (c) 2007-2021 Andy Maleh
         | 
| 2 | 
            +
            #
         | 
| 3 3 | 
             
            # Permission is hereby granted, free of charge, to any person obtaining
         | 
| 4 4 | 
             
            # a copy of this software and associated documentation files (the
         | 
| 5 5 | 
             
            # "Software"), to deal in the Software without restriction, including
         | 
| @@ -7,10 +7,10 @@ | |
| 7 7 | 
             
            # distribute, sublicense, and/or sell copies of the Software, and to
         | 
| 8 8 | 
             
            # permit persons to whom the Software is furnished to do so, subject to
         | 
| 9 9 | 
             
            # the following conditions:
         | 
| 10 | 
            -
            # | 
| 10 | 
            +
            #
         | 
| 11 11 | 
             
            # The above copyright notice and this permission notice shall be
         | 
| 12 12 | 
             
            # included in all copies or substantial portions of the Software.
         | 
| 13 | 
            -
            # | 
| 13 | 
            +
            #
         | 
| 14 14 | 
             
            # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
         | 
| 15 15 | 
             
            # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
         | 
| 16 16 | 
             
            # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
         | 
| @@ -51,6 +51,7 @@ module Glimmer | |
| 51 51 | 
             
                      observer.unobserve(observable, property)
         | 
| 52 52 | 
             
                    end
         | 
| 53 53 | 
             
                    alias unobserve unregister
         | 
| 54 | 
            +
                    alias deregister unregister
         | 
| 54 55 | 
             
                  end
         | 
| 55 56 |  | 
| 56 57 | 
             
                  class << self
         | 
| @@ -60,7 +61,7 @@ module Glimmer | |
| 60 61 | 
             
                  end
         | 
| 61 62 |  | 
| 62 63 | 
             
                  def registrations
         | 
| 63 | 
            -
                    @registrations ||= Set.new
         | 
| 64 | 
            +
                    @registrations ||= Concurrent::Set.new
         | 
| 64 65 | 
             
                  end
         | 
| 65 66 |  | 
| 66 67 | 
             
                  def registration_for(observable, property = nil)
         | 
| @@ -74,7 +75,7 @@ module Glimmer | |
| 74 75 | 
             
                  end
         | 
| 75 76 |  | 
| 76 77 | 
             
                  def dependents_for(registration)
         | 
| 77 | 
            -
                    dependents[registration] ||= Set.new
         | 
| 78 | 
            +
                    dependents[registration] ||= Concurrent::Set.new
         | 
| 78 79 | 
             
                  end
         | 
| 79 80 |  | 
| 80 81 | 
             
                  # registers observer in an observable on a property (optional)
         | 
| @@ -99,13 +100,14 @@ module Glimmer | |
| 99 100 | 
             
                  def unregister(observable, property = nil)
         | 
| 100 101 | 
             
                    return unless observable.is_a?(Observable)
         | 
| 101 102 | 
             
                    # TODO optimize performance in the future via indexing and/or making a registration official object/class
         | 
| 102 | 
            -
                    observable.remove_observer(*[self, property].compact)
         | 
| 103 103 | 
             
                    registration = registration_for(observable, property)
         | 
| 104 104 | 
             
                    dependents_for(registration).each do |dependent|
         | 
| 105 105 | 
             
                      dependent.unregister
         | 
| 106 106 | 
             
                      remove_dependent(registration => dependent)
         | 
| 107 107 | 
             
                    end
         | 
| 108 | 
            -
                    registrations.delete(registration)
         | 
| 108 | 
            +
                    registrations.delete(registration).tap do |registration|
         | 
| 109 | 
            +
                      observable.remove_observer(*[self, property].compact)
         | 
| 110 | 
            +
                    end
         | 
| 109 111 | 
             
                  end
         | 
| 110 112 | 
             
                  alias unobserve unregister
         | 
| 111 113 |  | 
    
        data/lib/glimmer/dsl/engine.rb
    CHANGED
    
    | @@ -1,5 +1,5 @@ | |
| 1 | 
            -
            # Copyright (c) 2007- | 
| 2 | 
            -
            # | 
| 1 | 
            +
            # Copyright (c) 2007-2021 Andy Maleh
         | 
| 2 | 
            +
            #
         | 
| 3 3 | 
             
            # Permission is hereby granted, free of charge, to any person obtaining
         | 
| 4 4 | 
             
            # a copy of this software and associated documentation files (the
         | 
| 5 5 | 
             
            # "Software"), to deal in the Software without restriction, including
         | 
| @@ -7,10 +7,10 @@ | |
| 7 7 | 
             
            # distribute, sublicense, and/or sell copies of the Software, and to
         | 
| 8 8 | 
             
            # permit persons to whom the Software is furnished to do so, subject to
         | 
| 9 9 | 
             
            # the following conditions:
         | 
| 10 | 
            -
            # | 
| 10 | 
            +
            #
         | 
| 11 11 | 
             
            # The above copyright notice and this permission notice shall be
         | 
| 12 12 | 
             
            # included in all copies or substantial portions of the Software.
         | 
| 13 | 
            -
            # | 
| 13 | 
            +
            #
         | 
| 14 14 | 
             
            # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
         | 
| 15 15 | 
             
            # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
         | 
| 16 16 | 
             
            # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
         | 
| @@ -28,7 +28,7 @@ module Glimmer | |
| 28 28 | 
             
              module DSL
         | 
| 29 29 | 
             
                # Glimmer DSL Engine
         | 
| 30 30 | 
             
                #
         | 
| 31 | 
            -
                # Follows Interpreter  | 
| 31 | 
            +
                # Follows Interpreter, Chain of Responsibility, and Singleton Design Patterns
         | 
| 32 32 | 
             
                #
         | 
| 33 33 | 
             
                # When DSL engine interprets an expression, it attempts to handle
         | 
| 34 34 | 
             
                # with ordered expression array specified via `.expressions=` method.
         | 
| @@ -51,19 +51,19 @@ module Glimmer | |
| 51 51 | 
             
                        end
         | 
| 52 52 | 
             
                        if interpretation
         | 
| 53 53 | 
             
                          interpretation
         | 
| 54 | 
            -
                        else | 
| 54 | 
            +
                        else
         | 
| 55 55 | 
             
                          raise Glimmer::Error, "Unsupported keyword: #{keyword}" unless static_expression_dsl || retrieved_static_expression
         | 
| 56 56 | 
             
                          Glimmer::DSL::Engine.dsl_stack.push(static_expression_dsl || Glimmer::DSL::Engine.dsl)
         | 
| 57 57 | 
             
                          static_expression = Glimmer::DSL::Engine.static_expressions[keyword][Glimmer::DSL::Engine.dsl]
         | 
| 58 | 
            -
                          if !static_expression.can_interpret?(Glimmer::DSL::Engine.parent, keyword, *args, &block)
         | 
| 59 | 
            -
                            raise Error, "Invalid use of Glimmer keyword #{keyword} with args #{args} under parent #{Glimmer::DSL::Engine.parent}"
         | 
| 58 | 
            +
                          if static_expression.nil? || !static_expression.can_interpret?(Glimmer::DSL::Engine.parent, keyword, *args, &block)
         | 
| 59 | 
            +
                            raise Error, "Invalid use of Glimmer keyword #{keyword} with args #{args} under parent #{Glimmer::DSL::Engine.parent.inspect}"
         | 
| 60 60 | 
             
                          else
         | 
| 61 61 | 
             
                            Glimmer::Config.logger.info {"#{static_expression.class.name} will handle expression keyword #{keyword}"}
         | 
| 62 62 | 
             
                            Glimmer::DSL::Engine.interpret_expression(static_expression, keyword, *args, &block)
         | 
| 63 63 | 
             
                          end
         | 
| 64 64 | 
             
                        end
         | 
| 65 | 
            -
                      end | 
| 66 | 
            -
                    end | 
| 65 | 
            +
                      end
         | 
| 66 | 
            +
                    end
         | 
| 67 67 | 
             
                  end
         | 
| 68 68 |  | 
| 69 69 | 
             
                  class << self
         | 
| @@ -86,7 +86,7 @@ module Glimmer | |
| 86 86 | 
             
                    end
         | 
| 87 87 |  | 
| 88 88 | 
             
                    def disabled_dsls
         | 
| 89 | 
            -
                      @disabled_dsls ||=  | 
| 89 | 
            +
                      @disabled_dsls ||= Concurrent::Array.new
         | 
| 90 90 | 
             
                    end
         | 
| 91 91 |  | 
| 92 92 | 
             
                    def enabled_dsls=(dsl_names)
         | 
| @@ -109,13 +109,13 @@ module Glimmer | |
| 109 109 |  | 
| 110 110 | 
             
                    # Dynamic expression chains of responsibility indexed by dsl
         | 
| 111 111 | 
             
                    def dynamic_expression_chains_of_responsibility
         | 
| 112 | 
            -
                      @dynamic_expression_chains_of_responsibility ||=  | 
| 112 | 
            +
                      @dynamic_expression_chains_of_responsibility ||= Concurrent::Hash.new
         | 
| 113 113 | 
             
                    end
         | 
| 114 114 |  | 
| 115 115 | 
             
                    # Static expressions indexed by keyword and dsl
         | 
| 116 116 | 
             
                    def static_expressions
         | 
| 117 | 
            -
                      @static_expressions ||=  | 
| 118 | 
            -
                    end | 
| 117 | 
            +
                      @static_expressions ||= Concurrent::Hash.new
         | 
| 118 | 
            +
                    end
         | 
| 119 119 |  | 
| 120 120 | 
             
                    # Sets dynamic expression chains of responsibility. Useful for internal testing
         | 
| 121 121 | 
             
                    attr_writer :dynamic_expression_chains_of_responsibility
         | 
| @@ -132,7 +132,7 @@ module Glimmer | |
| 132 132 | 
             
                    # Pattern when interpretting a DSL expression
         | 
| 133 133 | 
             
                    def add_dynamic_expressions(dsl_namespace, *expression_names)
         | 
| 134 134 | 
             
                      expression_names = expression_names.flatten
         | 
| 135 | 
            -
                      dsl = dsl_namespace.name.split("::").last.downcase.to_sym | 
| 135 | 
            +
                      dsl = dsl_namespace.name.split("::").last.downcase.to_sym
         | 
| 136 136 | 
             
                      dynamic_expression_chains_of_responsibility[dsl] = expression_names.reverse.map do |expression_name|
         | 
| 137 137 | 
             
                        expression_class(dsl_namespace, expression_name).new
         | 
| 138 138 | 
             
                      end.reduce(nil) do |last_expresion_handler, expression|
         | 
| @@ -140,14 +140,14 @@ module Glimmer | |
| 140 140 | 
             
                        expression_handler = ExpressionHandler.new(expression)
         | 
| 141 141 | 
             
                        expression_handler.next = last_expresion_handler if last_expresion_handler
         | 
| 142 142 | 
             
                        expression_handler
         | 
| 143 | 
            -
                      end | 
| 143 | 
            +
                      end
         | 
| 144 144 | 
             
                    end
         | 
| 145 145 |  | 
| 146 146 | 
             
                    def add_static_expression(static_expression)
         | 
| 147 147 | 
             
                      Glimmer::Config.logger.info {"Adding static expression: #{static_expression.class.name}"}
         | 
| 148 148 | 
             
                      keyword = static_expression.class.keyword
         | 
| 149 149 | 
             
                      static_expression_dsl = static_expression.class.dsl
         | 
| 150 | 
            -
                      static_expressions[keyword] ||=  | 
| 150 | 
            +
                      static_expressions[keyword] ||= Concurrent::Hash.new
         | 
| 151 151 | 
             
                      static_expressions[keyword][static_expression_dsl] = static_expression
         | 
| 152 152 | 
             
                      Glimmer.send(:define_method, keyword, &STATIC_EXPRESSION_METHOD_FACTORY.call(keyword))
         | 
| 153 153 | 
             
                    end
         | 
| @@ -161,10 +161,11 @@ module Glimmer | |
| 161 161 | 
             
                    end
         | 
| 162 162 |  | 
| 163 163 | 
             
                    # Interprets Glimmer dynamic DSL expression consisting of keyword, args, and block (e.g. shell(:no_resize) { ... })
         | 
| 164 | 
            -
                    def interpret(keyword, *args, &block) | 
| 164 | 
            +
                    def interpret(keyword, *args, &block)
         | 
| 165 165 | 
             
                      return puts(MESSAGE_NO_DSLS) if no_dsls?
         | 
| 166 166 | 
             
                      keyword = keyword.to_s
         | 
| 167 167 | 
             
                      dynamic_expression_dsl = (dynamic_expression_chains_of_responsibility.keys - disabled_dsls).first if dsl.nil?
         | 
| 168 | 
            +
                      # TODO consider pushing this code into interpret_expresion to provide hooks that work around it regardless of static vs dynamic
         | 
| 168 169 | 
             
                      dsl_stack.push(dynamic_expression_dsl || dsl)
         | 
| 169 170 | 
             
                      expression = dynamic_expression_chains_of_responsibility[dsl].handle(parent, keyword, *args, &block)
         | 
| 170 171 | 
             
                      interpret_expression(expression, keyword, *args, &block)
         | 
| @@ -185,7 +186,7 @@ module Glimmer | |
| 185 186 | 
             
                    def add_content(parent, expression, &block)
         | 
| 186 187 | 
             
                      if block_given? && expression.is_a?(ParentExpression)
         | 
| 187 188 | 
             
                        dsl_stack.push(expression.class.dsl)
         | 
| 188 | 
            -
                        parent_stack.push(parent) | 
| 189 | 
            +
                        parent_stack.push(parent)
         | 
| 189 190 | 
             
                        begin
         | 
| 190 191 | 
             
                          expression.add_content(parent, &block)
         | 
| 191 192 | 
             
                        ensure
         | 
| @@ -202,16 +203,16 @@ module Glimmer | |
| 202 203 | 
             
                    def_delegator :parent_stack, :last, :parent
         | 
| 203 204 |  | 
| 204 205 | 
             
                    def parent_stack
         | 
| 205 | 
            -
                      parent_stacks[dsl] ||=  | 
| 206 | 
            +
                      parent_stacks[dsl] ||= Concurrent::Array.new
         | 
| 206 207 | 
             
                    end
         | 
| 207 208 |  | 
| 208 209 | 
             
                    def parent_stacks
         | 
| 209 | 
            -
                      @parent_stacks ||=  | 
| 210 | 
            +
                      @parent_stacks ||= Concurrent::Hash.new
         | 
| 210 211 | 
             
                    end
         | 
| 211 212 |  | 
| 212 213 | 
             
                    # Enables multiple DSLs to play well with each other when mixing together
         | 
| 213 214 | 
             
                    def dsl_stack
         | 
| 214 | 
            -
                      @dsl_stack ||=  | 
| 215 | 
            +
                      @dsl_stack ||= Concurrent::Array.new
         | 
| 215 216 | 
             
                    end
         | 
| 216 217 | 
             
                  end
         | 
| 217 218 | 
             
                end
         |