glimmer 0.5.11 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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