glimmer 0.5.11 → 0.6.0

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.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/README.markdown +129 -15
  3. data/lib/glimmer.rb +13 -1
  4. data/lib/glimmer/css/rule_set.rb +27 -0
  5. data/lib/glimmer/css/style_sheet.rb +20 -0
  6. data/lib/glimmer/dsl/css/css_expression.rb +21 -0
  7. data/lib/glimmer/dsl/css/dsl.rb +10 -0
  8. data/lib/glimmer/dsl/css/p_expression.rb +25 -0
  9. data/lib/glimmer/dsl/css/property_expression.rb +22 -0
  10. data/lib/glimmer/dsl/css/rule_set_expression.rb +25 -0
  11. data/lib/glimmer/dsl/css/s_expression.rb +26 -0
  12. data/lib/glimmer/dsl/engine.rb +90 -18
  13. data/lib/glimmer/dsl/expression.rb +9 -4
  14. data/lib/glimmer/dsl/static_expression.rb +13 -13
  15. data/lib/glimmer/dsl/swt/async_exec_expression.rb +14 -0
  16. data/lib/glimmer/dsl/swt/bind_expression.rb +37 -0
  17. data/lib/glimmer/dsl/swt/color_expression.rb +17 -0
  18. data/lib/glimmer/dsl/swt/column_properties_expression.rb +24 -0
  19. data/lib/glimmer/dsl/swt/combo_selection_data_binding_expression.rb +42 -0
  20. data/lib/glimmer/dsl/swt/custom_widget_expression.rb +36 -0
  21. data/lib/glimmer/dsl/swt/data_binding_expression.rb +34 -0
  22. data/lib/glimmer/dsl/swt/display_expression.rb +19 -0
  23. data/lib/glimmer/dsl/swt/dsl.rb +26 -0
  24. data/lib/glimmer/dsl/swt/exec_expression.rb +28 -0
  25. data/lib/glimmer/dsl/swt/layout_data_expression.rb +25 -0
  26. data/lib/glimmer/dsl/swt/layout_expression.rb +27 -0
  27. data/lib/glimmer/dsl/swt/list_selection_data_binding_expression.rb +44 -0
  28. data/lib/glimmer/dsl/swt/menu_bar_expression.rb +33 -0
  29. data/lib/glimmer/dsl/swt/menu_expression.rb +32 -0
  30. data/lib/glimmer/dsl/swt/observe_expression.rb +32 -0
  31. data/lib/glimmer/dsl/swt/property_expression.rb +22 -0
  32. data/lib/glimmer/dsl/swt/rgb_expression.rb +12 -0
  33. data/lib/glimmer/dsl/swt/rgba_expression.rb +12 -0
  34. data/lib/glimmer/dsl/swt/shell_expression.rb +20 -0
  35. data/lib/glimmer/dsl/swt/swt_expression.rb +25 -0
  36. data/lib/glimmer/dsl/swt/sync_exec_expression.rb +15 -0
  37. data/lib/glimmer/dsl/swt/tab_item_expression.rb +33 -0
  38. data/lib/glimmer/dsl/swt/table_items_data_binding_expression.rb +31 -0
  39. data/lib/glimmer/dsl/swt/tree_items_data_binding_expression.rb +31 -0
  40. data/lib/glimmer/dsl/swt/tree_properties_expression.rb +26 -0
  41. data/lib/glimmer/dsl/swt/widget_expression.rb +27 -0
  42. data/lib/glimmer/dsl/swt/widget_listener_expression.rb +32 -0
  43. data/lib/glimmer/dsl/top_level_expression.rb +7 -0
  44. data/lib/glimmer/dsl/xml/dsl.rb +11 -0
  45. data/lib/glimmer/dsl/xml/html_expression.rb +25 -0
  46. data/lib/glimmer/dsl/xml/meta_expression.rb +23 -0
  47. data/lib/glimmer/dsl/xml/name_space_expression.rb +37 -0
  48. data/lib/glimmer/dsl/xml/node_parent_expression.rb +33 -0
  49. data/lib/glimmer/dsl/xml/tag_expression.rb +29 -0
  50. data/lib/glimmer/dsl/xml/text_expression.rb +22 -0
  51. data/lib/glimmer/dsl/xml/xml_expression.rb +21 -0
  52. data/lib/glimmer/rake_task.rb +1 -1
  53. data/lib/glimmer/swt/shell_proxy.rb +1 -2
  54. data/lib/glimmer/swt/widget_proxy.rb +6 -3
  55. data/lib/glimmer/ui/custom_widget.rb +8 -4
  56. data/lib/glimmer/ui/video.rb +31 -28
  57. data/lib/glimmer/xml/depth_first_search_iterator.rb +22 -0
  58. data/lib/glimmer/xml/name_space_visitor.rb +21 -0
  59. data/lib/glimmer/xml/node.rb +75 -0
  60. data/lib/glimmer/xml/node_visitor.rb +13 -0
  61. data/lib/glimmer/xml/xml_visitor.rb +65 -0
  62. data/samples/gladiator.rb +52 -12
  63. metadata +55 -31
  64. data/lib/glimmer/dsl.rb +0 -26
  65. data/lib/glimmer/dsl/async_exec_expression.rb +0 -12
  66. data/lib/glimmer/dsl/bind_expression.rb +0 -35
  67. data/lib/glimmer/dsl/color_expression.rb +0 -22
  68. data/lib/glimmer/dsl/column_properties_expression.rb +0 -22
  69. data/lib/glimmer/dsl/combo_selection_data_binding_expression.rb +0 -40
  70. data/lib/glimmer/dsl/custom_widget_expression.rb +0 -33
  71. data/lib/glimmer/dsl/data_binding_expression.rb +0 -32
  72. data/lib/glimmer/dsl/display_expression.rb +0 -14
  73. data/lib/glimmer/dsl/exec_expression.rb +0 -23
  74. data/lib/glimmer/dsl/layout_data_expression.rb +0 -23
  75. data/lib/glimmer/dsl/layout_expression.rb +0 -25
  76. data/lib/glimmer/dsl/list_selection_data_binding_expression.rb +0 -42
  77. data/lib/glimmer/dsl/menu_bar_expression.rb +0 -31
  78. data/lib/glimmer/dsl/menu_expression.rb +0 -30
  79. data/lib/glimmer/dsl/observe_expression.rb +0 -27
  80. data/lib/glimmer/dsl/property_expression.rb +0 -20
  81. data/lib/glimmer/dsl/shell_expression.rb +0 -16
  82. data/lib/glimmer/dsl/swt_expression.rb +0 -23
  83. data/lib/glimmer/dsl/sync_exec_expression.rb +0 -13
  84. data/lib/glimmer/dsl/tab_item_expression.rb +0 -31
  85. data/lib/glimmer/dsl/table_items_data_binding_expression.rb +0 -29
  86. data/lib/glimmer/dsl/tree_items_data_binding_expression.rb +0 -29
  87. data/lib/glimmer/dsl/tree_properties_expression.rb +0 -24
  88. data/lib/glimmer/dsl/widget_expression.rb +0 -25
  89. data/lib/glimmer/dsl/widget_listener_expression.rb +0 -30
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e6264cb7899c16ec9e6df0a24fc1365d1cd116633c6ce20010723badd50e4041
4
- data.tar.gz: 98e5d5bb061edaae3a139540c6e0b7721bdba5c703a4cb7ce26e3232e85f62f4
3
+ metadata.gz: 3610ccbe7872450d8b38005411e05be5b282c6f9785dbb21f87a239944ff304b
4
+ data.tar.gz: d80b1a110bd98b8dd5bd84be107ef9cd316af755cc052f94449b2249ddee1d4b
5
5
  SHA512:
6
- metadata.gz: d33841165b7d420be235057b4a95cf6f7a7ec6f4b3d04b7fcedd7e5233cdf2d3b3597bc83694fae30288ebf2f32741b9d1a0941be98472c1270190f2146a0890
7
- data.tar.gz: 627a9b85c3709fd097e7b2cbb54266091e9c83f5a2005a5d9e97fa3bff1c68b6a32d76f67f70f67f19f44254a12c65d3f22b064cd6351c42e1f7fcf11503b825
6
+ metadata.gz: 9d7810d076c698cab8d9c43fb4c7c3743ba37cad314e090e5d4112dcee50d6b5b5a389dce908e63e2c35a755079e944d69acff2b8ee9620f3541d474f97190a7
7
+ data.tar.gz: 64843e0799b6c035ca8aafa09be1ace82fda2ae7c188553e4db61ed8579b33598bc0f141ee90d8fb99f2383e810059278f2dfec8f4cbb862eac7d6e6288c0ae7
@@ -1,7 +1,7 @@
1
- # Glimmer 0.5.11 Beta (JRuby Desktop UI DSL + Data-Binding)
1
+ # Glimmer 0.6.0 Beta (JRuby Desktop UI DSL + Data-Binding)
2
2
  [![Coverage Status](https://coveralls.io/repos/github/AndyObtiva/glimmer/badge.svg?branch=master)](https://coveralls.io/github/AndyObtiva/glimmer?branch=master)
3
3
 
4
- Glimmer is a native-UI cross-platform desktop development library written in Ruby. Glimmer's main innovation is a JRuby DSL that enables productive and efficient authoring of desktop application user-interfaces while relying on the robust platform-native Eclipse SWT library. Glimmer additionally innovates by having built-in data-binding support to greatly facilitate synchronizing the UI with domain models. As a result, that achieves true decoupling of object oriented components, enabling developers to solve business problems without worrying about UI concerns, or alternatively drive development UI-first, and then write clean business components test-first afterwards.
4
+ Glimmer is a native-UI cross-platform desktop development library written in Ruby. Glimmer's main innovation is a JRuby DSL that enables productive and efficient authoring of desktop application user-interfaces while relying on the robust Eclipse SWT library. Glimmer additionally innovates by having built-in data-binding support to greatly facilitate synchronizing the UI with domain models. As a result, that achieves true decoupling of object oriented components, enabling developers to solve business problems without worrying about UI concerns, or alternatively drive development UI-first, and then write clean business components test-first afterwards.
5
5
 
6
6
  ## Examples
7
7
 
@@ -70,7 +70,7 @@ NOTE: Glimmer is in beta mode. Please help make better by adopting for small or
70
70
  ## Table of Contents
71
71
 
72
72
  <!-- TOC START min:1 max:3 link:true asterisk:false update:true -->
73
- - [Glimmer 0.5.11 Beta (JRuby Desktop UI DSL + Data-Binding)](#glimmer-058-beta-jruby-desktop-ui-dsl--data-binding)
73
+ - [Glimmer 0.6.0 Beta (JRuby Desktop UI DSL + Data-Binding)](#glimmer-058-beta-jruby-desktop-ui-dsl--data-binding)
74
74
  - [Examples](#examples)
75
75
  - [Hello World](#hello-world)
76
76
  - [Tic Tac Toe](#tic-tac-toe)
@@ -163,14 +163,14 @@ Please follow these instructions to make the `glimmer` command available on your
163
163
 
164
164
  Run this command to install directly:
165
165
  ```
166
- jgem install glimmer -v 0.5.11
166
+ jgem install glimmer -v 0.6.0
167
167
  ```
168
168
 
169
169
  ### Option 2: Bundler
170
170
 
171
171
  Add the following to `Gemfile`:
172
172
  ```
173
- gem 'glimmer', '~> 0.5.11'
173
+ gem 'glimmer', '~> 0.6.0'
174
174
  ```
175
175
 
176
176
  And, then run:
@@ -1558,6 +1558,119 @@ shell(:no_resize) {
1558
1558
 
1559
1559
  Also, you may invoke `Display.setAppVersion('1.0.0')` if needed for OS app version identification reasons during development, replacing `'1.0.0'` with your application version.
1560
1560
 
1561
+ #### Multi-DSL Support
1562
+
1563
+ Glimmer supports two other DSLs in addition to the SWT DSL; that is Glimmer XML DSL and Glimmer CSS DSL. It also allows mixing DSLs, which comes in handy when doing things like using the `browser` widget. Glimmer automatically recognizes top-level keywords in each DSL
1564
+ and switches DSLs accordingly until it finishes processes the top-level keywords, at which point it switches back to the prior DSL.
1565
+
1566
+ For example, the SWT DSL has the following top-level keywords:
1567
+ - `shell`
1568
+ - `display`
1569
+ - `observe`
1570
+ - `async_exec`
1571
+ - `sync_exec`
1572
+
1573
+ ##### XML DSL
1574
+
1575
+ Simply start with `html` keyword and add HTML inside its block using Glimmer DSL syntax.
1576
+ Once done, you may call `to_s`, `to_xml`, or `to_html` to get the formatted HTML output.
1577
+
1578
+ Here are all the Glimmer XML DSL top-level keywords:
1579
+ - `html`
1580
+ - `tag`: enables custom tag creation for exceptional cases by passing tag name as '_name' attribute
1581
+ - `name_space`: enables namespacing html tags
1582
+
1583
+ Element properties are typically passed as a key/value hash (e.g. `section(id: 'main', class: 'accordion')`) . However, for properties like "selected" or "checked", you must leave value `nil` or otherwise pass in front of the hash (e.g. `input(:checked, type: 'checkbox')` )
1584
+
1585
+ Example (basic HTML / you may copy/paste in [`girb`](#girb-glimmer-irb-command)):
1586
+
1587
+ ```ruby
1588
+ @xml = html {
1589
+ head {
1590
+ meta(name: "viewport", content: "width=device-width, initial-scale=2.0")
1591
+ }
1592
+ body {
1593
+ h1 { "Hello, World!" }
1594
+ }
1595
+ }
1596
+ puts @xml
1597
+ ```
1598
+
1599
+ Output:
1600
+
1601
+ ```
1602
+ <html><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=2.0\" /></head><body><h1>Hello, World!</h1></body></html>
1603
+ ```
1604
+
1605
+ Example (explicit XML tag / you may copy/paste in [`girb`](#girb-glimmer-irb-command)):
1606
+
1607
+ ```ruby
1608
+ puts tag(:_name => "DOCUMENT")
1609
+ ```
1610
+
1611
+ Output:
1612
+
1613
+ ```
1614
+ <DOCUMENT/>
1615
+ ```
1616
+
1617
+ Example (XML namespaces using `name_space` keyword / you may copy/paste in [`girb`](#girb-glimmer-irb-command)):
1618
+
1619
+ ```ruby
1620
+ @xml = name_space(:w3c) {
1621
+ html(:id => "thesis", :class => "document") {
1622
+ body(:id => "main") {
1623
+ }
1624
+ }
1625
+ }
1626
+ puts @xml
1627
+ ```
1628
+
1629
+ Output:
1630
+
1631
+ ```
1632
+ <w3c:html id=\"thesis\" class=\"document\"><w3c:body id=\"main\"></w3c:body></w3c:html>
1633
+ ```
1634
+
1635
+ Example (XML namespaces using dot operator / you may copy/paste in [`girb`](#girb-glimmer-irb-command)):
1636
+
1637
+ ```ruby
1638
+ @xml = tag(:_name => "DOCUMENT") {
1639
+ document.body(document.id => "main") {
1640
+ }
1641
+ }
1642
+ puts @xml
1643
+ ```
1644
+
1645
+ Output:
1646
+
1647
+ ```
1648
+ <DOCUMENT><document:body document:id="main"></document:body></DOCUMENT>
1649
+ ```
1650
+
1651
+
1652
+ ##### CSS DSL
1653
+
1654
+ Simply start with `css` keyword and add stylesheet rule sets inside its block using Glimmer DSL syntax.
1655
+ Once done, you may call `to_s` or `to_css` to get the formatted CSS output.
1656
+
1657
+ `css` is the only top-level keyword in the Glimmer CSS DSL
1658
+
1659
+ Example (you may copy/paste in [`girb`](#girb-glimmer-irb-command)):
1660
+
1661
+ ```ruby
1662
+ @css = css {
1663
+ body {
1664
+ font_size "1.1em"
1665
+ }
1666
+
1667
+ s('body > h1') {
1668
+ background_color :red
1669
+ }
1670
+ }
1671
+ puts @css
1672
+ ```
1673
+
1561
1674
  #### Video Widget
1562
1675
 
1563
1676
  ![Video Widget](images/glimmer-video-widget.png)
@@ -1662,15 +1775,14 @@ Example rendering HTML with JavaScript on document ready (you may copy/paste in
1662
1775
  shell {
1663
1776
  minimum_size 130, 130
1664
1777
  @browser = browser {
1665
- text <<~HTML
1666
- <html>
1667
- <head>
1668
- </head>
1669
- <body>
1670
- <h1>Hello, World!</h1>
1671
- </body>
1672
- </html>
1673
- HTML
1778
+ text html {
1779
+ head {
1780
+ meta(name: "viewport", content: "width=device-width, initial-scale=2.0")
1781
+ }
1782
+ body {
1783
+ h1 { "Hello, World!" }
1784
+ }
1785
+ }
1674
1786
  on_completed { # on load of the page execute this JavaScript
1675
1787
  @browser.swt_widget.execute("alert('Hello, World!');")
1676
1788
  }
@@ -1678,6 +1790,8 @@ shell {
1678
1790
  }.open
1679
1791
  ```
1680
1792
 
1793
+ This relies on Glimmer's [Multi-DSL Support](https://github.com/AndyObtiva/glimmer/tree/development#multi-dsl-support) for building the HTML text using Glimmer XML DSL.
1794
+
1681
1795
  ## Glimmer Style Guide
1682
1796
 
1683
1797
  - Widgets are declared with underscored lowercase versions of their SWT names minus the SWT package name.
@@ -1917,7 +2031,7 @@ Glimmer employs smart defaults in packaging.
1917
2031
 
1918
2032
  The package application name (shows up in top menu bar on the Mac) will be a human form of the app root directory name (e.g. "Math Bowling" for "MathBowling" or "math_bowling" app root directory name). However, application name and version may be specified explicitly via "-Bmac.CFBundleName" and "-Bmac.CFBundleVersion" options.
1919
2033
 
1920
- Also, the package will only include these directories: app, config, db, lib, script, bin, images, sounds, videos
2034
+ Also, the package will only include these directories: app, config, db, lib, script, bin, docs, fonts, images, sounds, videos
1921
2035
 
1922
2036
  After running once, you will find a `config/warble.rb` file. It has the JAR packaging configuration. You may adjust included directories in it if needed, and then rerun `rake glimmer:package` and it will pick up your custom configuration. Alternatively, if you'd like to customize the included directories to begin with, don't run `rake glimmer:package` right away. Run this command first:
1923
2037
 
@@ -54,6 +54,16 @@ module Glimmer
54
54
  def enable_logging
55
55
  @@logger = Logger.new(STDOUT).tap {|logger| logger.level = Logger::WARN}
56
56
  end
57
+
58
+ # Sets current DSL (e.g. :swt)
59
+ def dsl=(dsl_name)
60
+ Glimmer::DSL::Engine.dsl = dsl_name
61
+ end
62
+
63
+ # Currently set DSL (e.g. :swt or :xml)
64
+ def dsl
65
+ Glimmer::DSL::Engine.dsl
66
+ end
57
67
  end
58
68
 
59
69
  def method_missing(method_symbol, *args, &block)
@@ -82,7 +92,9 @@ $LOAD_PATH.unshift(File.expand_path('..', __FILE__))
82
92
  require 'glimmer/launcher'
83
93
  require Glimmer::Launcher.swt_jar_file
84
94
  require 'glimmer/swt/packages'
85
- require 'glimmer/dsl'
95
+ require 'glimmer/dsl/swt/dsl'
96
+ require 'glimmer/dsl/xml/dsl'
97
+ require 'glimmer/dsl/css/dsl'
86
98
  require 'glimmer/error'
87
99
  require 'glimmer/invalid_keyword_error'
88
100
  require 'glimmer/ui/video'
@@ -0,0 +1,27 @@
1
+ module Glimmer
2
+ module CSS
3
+ class RuleSet
4
+ attr_reader :selector, :properties
5
+
6
+ def initialize(selector)
7
+ @selector = selector
8
+ @properties = {}
9
+ end
10
+
11
+ def add_property(keyword, *args)
12
+ keyword = keyword.to_s.downcase.gsub('_', '-')
13
+ @properties[keyword] = args.first
14
+ end
15
+
16
+ def to_css
17
+ css = "#{@selector} {\n"
18
+ @properties.each do |name, value|
19
+ css << " #{name}: #{value};\n"
20
+ end
21
+ css << "}"
22
+ end
23
+
24
+ alias to_s to_css
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,20 @@
1
+ require 'glimmer/css/rule_set'
2
+
3
+ module Glimmer
4
+ module CSS
5
+ class StyleSheet
6
+ attr_reader :rule_sets
7
+
8
+ def initialize
9
+ @rule_sets = []
10
+ end
11
+
12
+ def to_css
13
+ rule_set_css = rule_sets.map(&:to_css).join("\n\n")
14
+ "#{rule_set_css}\n"
15
+ end
16
+
17
+ alias to_s to_css
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,21 @@
1
+ require 'glimmer/dsl/static_expression'
2
+ require 'glimmer/dsl/top_level_expression'
3
+ require 'glimmer/dsl/parent_expression'
4
+ require 'glimmer/css/style_sheet'
5
+
6
+ module Glimmer
7
+ module DSL
8
+ module CSS
9
+ # This static html expression flips the DSL switch on for
10
+ # XML DSL in Glimmer
11
+ class CssExpression < StaticExpression
12
+ include TopLevelExpression
13
+ include ParentExpression
14
+
15
+ def interpret(parent, keyword, *args, &block)
16
+ Glimmer::CSS::StyleSheet.new
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,10 @@
1
+ require 'glimmer/dsl/engine'
2
+ Dir[File.expand_path('../*_expression.rb', __FILE__)].each {|f| require f}
3
+
4
+ Glimmer::DSL::Engine.add_dynamic_expressions(
5
+ Glimmer::DSL::CSS,
6
+ %w[
7
+ rule_set
8
+ property
9
+ ]
10
+ )
@@ -0,0 +1,25 @@
1
+ require 'glimmer/dsl/static_expression'
2
+ require 'glimmer/css/style_sheet'
3
+ require 'glimmer/css/rule_set'
4
+
5
+ module Glimmer
6
+ module DSL
7
+ module CSS
8
+ class PExpression < StaticExpression
9
+ include ParentExpression
10
+
11
+ def can_interpret?(parent, keyword, *args, &block)
12
+ keyword == 'p' and
13
+ parent.is_a?(Glimmer::CSS::RuleSet) and
14
+ !block_given? and
15
+ !args.empty? and
16
+ args.size > 1
17
+ end
18
+
19
+ def interpret(parent, keyword, *args, &block)
20
+ parent.add_property(args[0], args[1])
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,22 @@
1
+ require 'glimmer/dsl/expression'
2
+ require 'glimmer/css/rule_set'
3
+
4
+ module Glimmer
5
+ module DSL
6
+ module CSS
7
+ class PropertyExpression < Expression
8
+ include ParentExpression
9
+
10
+ def can_interpret?(parent, keyword, *args, &block)
11
+ parent.is_a?(Glimmer::CSS::RuleSet) and
12
+ !block_given? and
13
+ !args.empty?
14
+ end
15
+
16
+ def interpret(parent, keyword, *args, &block)
17
+ parent.add_property(keyword, *args)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,25 @@
1
+ require 'glimmer/dsl/expression'
2
+ require 'glimmer/css/style_sheet'
3
+ require 'glimmer/css/rule_set'
4
+
5
+ module Glimmer
6
+ module DSL
7
+ module CSS
8
+ class RuleSetExpression < Expression
9
+ include ParentExpression
10
+
11
+ def can_interpret?(parent, keyword, *args, &block)
12
+ parent.is_a?(Glimmer::CSS::StyleSheet) and
13
+ block_given? and
14
+ args.empty?
15
+ end
16
+
17
+ def interpret(parent, keyword, *args, &block)
18
+ Glimmer::CSS::RuleSet.new(keyword.to_s.downcase).tap do |rule_set|
19
+ parent.rule_sets << rule_set
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,26 @@
1
+ require 'glimmer/dsl/static_expression'
2
+ require 'glimmer/css/style_sheet'
3
+ require 'glimmer/css/rule_set'
4
+
5
+ module Glimmer
6
+ module DSL
7
+ module CSS
8
+ class SExpression < StaticExpression
9
+ include ParentExpression
10
+
11
+ def can_interpret?(parent, keyword, *args, &block)
12
+ keyword == 's' and
13
+ parent.is_a?(Glimmer::CSS::StyleSheet) and
14
+ block_given? and
15
+ !args.empty?
16
+ end
17
+
18
+ def interpret(parent, keyword, *args, &block)
19
+ Glimmer::CSS::RuleSet.new(args.first.to_s).tap do |rule_set|
20
+ parent.rule_sets << rule_set
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,5 +1,4 @@
1
1
  require 'glimmer'
2
- Dir[File.expand_path('../*_expression.rb', __FILE__)].each {|f| require f}
3
2
  require 'glimmer/dsl/expression_handler'
4
3
 
5
4
  module Glimmer
@@ -10,12 +9,31 @@ module Glimmer
10
9
  #
11
10
  # When DSL engine interprets an expression, it attempts to handle
12
11
  # with ordered expression array specified via `.expressions=` method.
13
- #
14
- # TODO support auto-loading static_expressions in the future for expressions where
15
- # the keyword does not vary dynamically. These static keywords are then
16
- # predefined as methods in Glimmer instead of needing method_missing
17
12
  class Engine
18
13
  class << self
14
+ def dsl=(dsl_name)
15
+ dsl_name = dsl_name&.to_sym
16
+ if dsl_name
17
+ dsl_stack.push(dsl_name)
18
+ else
19
+ dsl_stack.clear
20
+ end
21
+ end
22
+
23
+ def dsl
24
+ dsl_stack.last
25
+ end
26
+
27
+ # Dynamic expression chains of responsibility indexed by dsl
28
+ def dynamic_expression_chains_of_responsibility
29
+ @dynamic_expression_chains_of_responsibility ||= {}
30
+ end
31
+
32
+ # Static expressions indexed by keyword and dsl
33
+ def static_expressions
34
+ @static_expressions ||= {}
35
+ end
36
+
19
37
  # Sets an ordered array of DSL expressions to support
20
38
  #
21
39
  # Every expression has an underscored name corresponding to an upper
@@ -23,33 +41,75 @@ module Glimmer
23
41
  #
24
42
  # They are used in order following the Chain of Responsibility Design
25
43
  # Pattern when interpretting a DSL expression
26
- #
27
- # TODO rename to dynamic_expressions in the future when supporting static expressions
28
- def dynamic_expressions=(expression_names)
29
- @dynamic_expression_chain_of_responsibility = expression_names.reverse.reduce(nil) do |last_expresion_handler, expression_name|
30
- Glimmer.logger&.debug "Loading #{expression_class_name(expression_name)}..."
31
- expression = expression_class(expression_name).new
44
+ def add_dynamic_expressions(dsl_namespace, expression_names)
45
+ dsl = dsl_namespace.name.split("::").last.downcase.to_sym
46
+ dynamic_expression_chains_of_responsibility[dsl] = expression_names.reverse.map do |expression_name|
47
+ expression_class(dsl_namespace, expression_name).new
48
+ end.reduce(nil) do |last_expresion_handler, expression|
49
+ Glimmer.logger&.debug "Adding dynamic expression: #{expression.class.name}"
32
50
  expression_handler = ExpressionHandler.new(expression)
33
51
  expression_handler.next = last_expresion_handler if last_expresion_handler
34
52
  expression_handler
35
53
  end
36
54
  end
37
55
 
38
- def expression_class(expression_name)
39
- DSL.const_get(expression_class_name(expression_name).to_sym)
56
+ def add_static_expression(static_expression)
57
+ Glimmer.logger&.debug "Adding static expression: #{static_expression.class.name}"
58
+ keyword = static_expression.class.keyword
59
+ static_expression_dsl = static_expression.class.dsl
60
+ static_expressions[keyword] ||= {}
61
+ static_expressions[keyword][static_expression_dsl] = static_expression
62
+ Glimmer.define_method(keyword) do |*args, &block|
63
+ begin
64
+ retrieved_static_expression = Glimmer::DSL::Engine.static_expressions[keyword][Glimmer::DSL::Engine.dsl]
65
+ static_expression_dsl = Glimmer::DSL::Engine.static_expressions[keyword].keys.first if retrieved_static_expression.nil?
66
+ if retrieved_static_expression.nil? && Glimmer::DSL::Engine.dsl && (static_expression_dsl.nil? || !Glimmer::DSL::Engine.static_expressions[keyword][static_expression_dsl].is_a?(TopLevelExpression))
67
+ begin
68
+ return Glimmer::DSL::Engine.interpret(keyword, *args, &block)
69
+ rescue => e
70
+ raise e if static_expression_dsl.nil?
71
+ end
72
+ end
73
+ raise Glimmer::Error, "Unsupported keyword: #{keyword}" unless static_expression_dsl || retrieved_static_expression
74
+ Glimmer::DSL::Engine.dsl_stack.push(static_expression_dsl || Glimmer::DSL::Engine.dsl)
75
+ static_expression = Glimmer::DSL::Engine.static_expressions[keyword][Glimmer::DSL::Engine.dsl]
76
+ if !static_expression.can_interpret?(Glimmer::DSL::Engine.parent, keyword, *args, &block)
77
+ raise Error, "Invalid use of Glimmer keyword #{keyword} with args #{args} under parent #{Glimmer::DSL::Engine.parent}"
78
+ else
79
+ Glimmer.logger&.debug "#{static_expression.class.name} will handle expression keyword #{keyword}"
80
+ return static_expression.interpret(Glimmer::DSL::Engine.parent, keyword, *args, &block).tap do |ui_object|
81
+ Glimmer::DSL::Engine.add_content(ui_object, static_expression, &block) unless block.nil?
82
+ Glimmer::DSL::Engine.dsl_stack.pop
83
+ end
84
+ end
85
+ rescue => e
86
+ Glimmer::DSL::Engine.dsl_stack.pop
87
+ raise e
88
+ end
89
+ end
90
+ end
91
+
92
+ def expression_class(dsl_namespace, expression_name)
93
+ dsl_namespace.const_get(expression_class_name(expression_name).to_sym)
40
94
  end
41
95
 
42
96
  def expression_class_name(expression_name)
43
97
  "#{expression_name}_expression".camelcase(:upper)
44
98
  end
45
99
 
46
- # Interprets Glimmer DSL keyword, args, and block (e.g. shell(:no_resize) { ... })
100
+ # Interprets Glimmer dynamic DSL expression consisting of keyword, args, and block (e.g. shell(:no_resize) { ... })
47
101
  def interpret(keyword, *args, &block)
48
102
  keyword = keyword.to_s
49
- expression = @dynamic_expression_chain_of_responsibility.handle(current_parent, keyword, *args, &block)
50
- expression.interpret(current_parent, keyword, *args, &block).tap do |ui_object|
103
+ dynamic_expression_dsl = dynamic_expression_chains_of_responsibility.keys.first if dsl.nil?
104
+ dsl_stack.push(dynamic_expression_dsl || dsl)
105
+ expression = dynamic_expression_chains_of_responsibility[dsl].handle(parent, keyword, *args, &block)
106
+ expression.interpret(parent, keyword, *args, &block).tap do |ui_object|
51
107
  add_content(ui_object, expression, &block)
108
+ dsl_stack.pop
52
109
  end
110
+ rescue => e
111
+ dsl_stack.pop
112
+ raise e
53
113
  end
54
114
 
55
115
  # Adds content block to parent UI object
@@ -58,21 +118,33 @@ module Glimmer
58
118
  #
59
119
  # For example, a shell widget would get properties set and children added
60
120
  def add_content(parent, expression, &block)
121
+ time = Time.now.to_f
122
+ dsl_stack.push(expression.class.dsl)
61
123
  parent_stack.push(parent) if expression.is_a?(ParentExpression)
62
124
  expression.add_content(parent, &block) if block_given?
63
125
  parent_stack.pop if expression.is_a?(ParentExpression)
126
+ dsl_stack.pop
64
127
  end
65
128
 
66
129
  # Current parent while evaluating Glimmer DSL (nil if just started or done evaluatiing)
67
130
  #
68
131
  # Parents are maintained in a stack while evaluating Glimmer DSL
69
132
  # to ensure properly ordered interpretation of DSL syntax
70
- def current_parent
133
+ def parent
71
134
  parent_stack.last
72
135
  end
73
136
 
74
137
  def parent_stack
75
- @parent_stack ||= []
138
+ parent_stacks[dsl] ||= []
139
+ end
140
+
141
+ def parent_stacks
142
+ @parent_stacks ||= {}
143
+ end
144
+
145
+ # Enables multiple DSLs to play well with each other when mixing together
146
+ def dsl_stack
147
+ @dsl_stack ||= []
76
148
  end
77
149
  end
78
150
  end