Skip to content

Commit

Permalink
- Support ability to interpret multiple DSL expression hierarchies, b…
Browse files Browse the repository at this point in the history
…y suspending interpretation of a hierarchy, interpreting another until done, and then resuming interpretation of previous hierarchy until done too. That is done by starting a new expression hierarchy interpretation using `Glimmer::DSL::Engine::new_parent_stack` in the middle of interpreting another expression hierarchy.

- Refactor/rename `Glimmer::DSL::Engine::parent_stacks` to `Glimmer::DSL::Engine::dsl_parent_stacks` and have it include an `Array` of `Array`s of parent stacks per DSL.
  • Loading branch information
AndyObtiva committed Jul 14, 2024
1 parent e66f91a commit d4035b4
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 10 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
Related Change Logs:
- [glimmer-dsl-swt/CHANGELOG.md](https://github.com/AndyObtiva/glimmer-dsl-swt/blob/master/CHANGELOG.md)

### 2.8.0

- Support ability to interpret multiple DSL expression hierarchies, by suspending interpretation of a hierarchy, interpreting another until done, and then resuming interpretation of previous hierarchy until done too. That is done by starting a new expression hierarchy interpretation using `Glimmer::DSL::Engine::new_parent_stack` in the middle of interpreting another expression hierarchy.
- Refactor/rename `Glimmer::DSL::Engine::parent_stacks` to `Glimmer::DSL::Engine::dsl_parent_stacks` and have it include an `Array` of `Array`s of parent stacks per DSL.

### 2.7.9

- Optimize performance of `Glimmer::DataBinding::ObservableModel#add_observer` by removing `OpenStruct` constant check.
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 style="position: relative; top: 20px;" />](https://rubygems.org/gems/glimmer) Glimmer 2.7.9
# [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 style="position: relative; top: 20px;" />](https://rubygems.org/gems/glimmer) Glimmer 2.8.0
## DSL Framework for Ruby GUI and More
[![Gem Version](https://badge.fury.io/rb/glimmer.svg)](http://badge.fury.io/rb/glimmer)
[![rspec](https://github.com/AndyObtiva/glimmer/workflows/rspec/badge.svg)](https://github.com/AndyObtiva/glimmer/actions?query=workflow%3Arspec)
Expand Down Expand Up @@ -268,7 +268,7 @@ end
### Setup

Follow these steps to author a [Glimmer](https://rubygems.org/gems/glimmer) DSL:
- Add `gem 'glimmer', '~> 2.7.9'` to `Gemfile` and run `bundle` or run `gem install glimmer -v2.7.9` and add `require 'glimmer'`
- Add `gem 'glimmer', '~> 2.8.0'` to `Gemfile` and run `bundle` or run `gem install glimmer -v2.8.0` and add `require 'glimmer'`
- Create `glimmer/dsl/[dsl_name]/dsl.rb`, which requires and adds all dynamic expressions for the [dsl_name] Glimmer DSL module as per the code shown in the previous section (or [Official DSLs](#official-dsls) as examples)
- Create `glimmer/dsl/[dsl_name]/[expresion_name]_expresion.rb` for every [expresion_name] expression needed, whether dynamic or static

Expand Down
3 changes: 2 additions & 1 deletion TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Related TODO files:
- Observe multiple attributes (e.g. observe(@game, [:width, :height]) returns |value, attribute_name|)
- Fix issue with computed data-binding when combined with nested/indexed data-binding (it looks up computed attributes on root object instead of nested object, it seems)
- Support nested computed attributes (e.g. computed_by: {address1: [:street, :city, :state, :zip]})
- Consider the idea of having Observer#observe accept an optional block to do observation without implementing `call` (kinda like when using the `observe` keyword in the Glimmer DSL).
- Consider the idea of having Observer#observe accept an optional block to do observation without implementing `call` (kinda like when using the `observe` keyword in the Glimmer DSL).
- Ensure removing observers from hash in ObservableModel when removed from observable
- Avoid `< Struct.new` in specs (tests)
- Add built-in support to Glimmer::DSL::Engine to memoize/cache expressions similar to how that is supported for StaticExpression (but allowing an outside keyword and non-static expression to be used)
Expand Down Expand Up @@ -57,6 +57,7 @@ Related TODO files:
- Support `recursive: true` with models that have nested models
- Observe multiple attributes or indexed/keyed/nested attribute expressions with a single observer
- Consider the idea of having before_read and before_write support cancelling a data-binding operation by returning `false`, returning `:cancel`, Or by receiving an extra arg that enables calling arg.cancel on or something similar to avoid having normal code cancel the data-binding operation just because it returns nil.
- Consider supporting concurrent/parallel interpretation of expression hierarchies by assigning each one an ID that is used to identify it if multiple hierarchies were interpreted in multiple concurrent/parallel threads.

### Miscellaneous

Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.7.9
2.8.0
32 changes: 26 additions & 6 deletions lib/glimmer/dsl/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def enabled_dsls=(dsl_names)

# Resets Glimmer's engine activity and configuration. Useful in rspec before or after blocks in tests.
def reset
parent_stacks.values.each do |a_parent_stack|
dsl_parent_stacks.values.each do |a_parent_stack|
a_parent_stack.clear
end
dsl_stack.clear
Expand Down Expand Up @@ -230,11 +230,11 @@ def interpret_expression(expression, keyword, *args, &block)
def add_content(new_parent, expression, keyword, *args, &block)
if block_given? && expression.is_a?(ParentExpression)
dsl_stack.push(expression.class.dsl)
parent_stack.push(new_parent)
push_parent_into_parent_stack(new_parent)
begin
expression.add_content(new_parent, keyword, *args, &block)
ensure
parent_stack.pop
pop_parent_from_parent_stack
dsl_stack.pop
end
end
Expand All @@ -244,14 +244,34 @@ def add_content(new_parent, expression, keyword, *args, &block)
#
# Parents are maintained in a stack while evaluating Glimmer DSL
# to ensure properly ordered interpretation of DSL syntax
def_delegator :parent_stack, :last, :parent
def parent
parent_stack.last
end

def push_parent_into_parent_stack(parent)
parent_stack.push(parent)
end

def pop_parent_from_parent_stack
parent_stack.pop
parent_stacks.pop if parent_stacks.size > 1 && parent_stacks.last.empty?
end

def parent_stack
parent_stacks[dsl] ||= Concurrent::Array.new
new_parent_stack if parent_stacks.last.nil?
parent_stacks.last
end

def new_parent_stack
parent_stacks.push(Concurrent::Array.new)
end

def parent_stacks
@parent_stacks ||= Concurrent::Hash.new
dsl_parent_stacks[dsl] ||= Concurrent::Array.new # TODO insted of having one array, we need to nest it within an array of arrays
end

def dsl_parent_stacks
@dsl_parent_stacks ||= Concurrent::Hash.new
end

# Enables multiple DSLs to play well with each other when mixing together
Expand Down
18 changes: 18 additions & 0 deletions spec/lib/glimmer/dsl/engine_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,24 @@ module GlimmerSpec
expect(GLIMMER_TOP_LEVEL_TARGET.to_s).to eq('SWT shell { SWT Dynamic browser(XML html { XML Dynamic body { XML Dynamic input({:type=>"text", :value=>"Hello, World!"}) } }) }')
end

it 'interprets another expression hierarchy in the middle of interpreting an expression hierarchy' do
@target1 = shell {
spinner {
# start a second hierarchy
Glimmer::DSL::Engine.new_parent_stack
@target2 = shell {
table {
}
}
# continue back in first hierarchy
progress
}
}

expect(@target1.to_s).to eq('SWT shell { SWT Dynamic spinner { SWT Dynamic progress } }')
expect(@target2.to_s).to eq('SWT shell { SWT Dynamic table }')
end

it 'standard static expression' do
@target = shell {
}
Expand Down

0 comments on commit d4035b4

Please sign in to comment.