glimmer-dsl-opal 0.0.4 → 0.0.9
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 +35 -0
 - data/README.md +983 -34
 - data/VERSION +1 -1
 - data/lib/glimmer-dsl-opal.rb +5 -2
 - data/lib/glimmer/data_binding/ext/observable_model.rb +40 -0
 - data/lib/glimmer/data_binding/table_items_binding.rb +70 -0
 - data/lib/glimmer/dsl/opal/async_exec_expression.rb +17 -0
 - data/lib/glimmer/dsl/opal/browser_expression.rb +17 -0
 - data/lib/glimmer/dsl/opal/column_properties_expression.rb +22 -0
 - data/lib/glimmer/dsl/opal/dsl.rb +11 -0
 - data/lib/glimmer/dsl/opal/message_box_expression.rb +20 -0
 - data/lib/glimmer/dsl/opal/observe_expression.rb +32 -0
 - data/lib/glimmer/dsl/opal/tab_folder_expression.rb +17 -0
 - data/lib/glimmer/dsl/opal/tab_item_expression.rb +17 -0
 - data/lib/glimmer/dsl/opal/table_column_expression.rb +17 -0
 - data/lib/glimmer/dsl/opal/table_expression.rb +17 -0
 - data/lib/glimmer/dsl/opal/table_items_data_binding_expression.rb +29 -0
 - data/lib/glimmer/opal/display_proxy.rb +23 -0
 - data/lib/glimmer/opal/div_proxy.rb +11 -2
 - data/lib/glimmer/opal/document_proxy.rb +124 -4
 - data/lib/glimmer/opal/element_proxy.rb +45 -14
 - data/lib/glimmer/opal/grid_layout_proxy.rb +3 -1
 - data/lib/glimmer/opal/iframe_proxy.rb +23 -0
 - data/lib/glimmer/opal/input_proxy.rb +8 -4
 - data/lib/glimmer/opal/label_proxy.rb +1 -1
 - data/lib/glimmer/opal/layout_data_proxy.rb +23 -2
 - data/lib/glimmer/opal/list_proxy.rb +2 -2
 - data/lib/glimmer/opal/modal.rb +94 -0
 - data/lib/glimmer/opal/point.rb +5 -0
 - data/lib/glimmer/opal/select_proxy.rb +1 -1
 - data/lib/glimmer/opal/tab_folder.rb +53 -0
 - data/lib/glimmer/opal/tab_item.rb +98 -0
 - data/lib/glimmer/opal/table_column.rb +50 -0
 - data/lib/glimmer/opal/table_item.rb +136 -0
 - data/lib/glimmer/opal/table_proxy.rb +149 -0
 - data/lib/samples/elaborate/contact_manager.rb +1 -2
 - data/lib/samples/elaborate/login.rb +0 -1
 - data/lib/samples/elaborate/tic_tac_toe.rb +5 -5
 - data/lib/samples/hello/hello_tab.rb +2 -2
 - metadata +28 -16
 - data/lib/glimmer/config.rb +0 -22
 - data/lib/glimmer/dsl/engine.rb +0 -193
 - data/lib/glimmer/dsl/expression.rb +0 -42
 - data/lib/glimmer/dsl/expression_handler.rb +0 -48
 - data/lib/glimmer/dsl/parent_expression.rb +0 -12
 - data/lib/glimmer/dsl/static_expression.rb +0 -36
 - data/lib/glimmer/dsl/top_level_expression.rb +0 -7
 - data/lib/glimmer/error.rb +0 -6
 - data/lib/glimmer/invalid_keyword_error.rb +0 -6
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: b56026edb0b7ab096e2b972afcc99f2914db153e52fa52616859b44e86d0ad8c
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: aa94ad9ded4e7cac3ec706db46a012861e9c1e3a0d0026cdcc7833f43733eba0
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 66e958ca4e486e0a33908fb21d72322c375da35774a86e0514898a50b214bff0ecd7e7f4f5ce930983394cf49d9386ddce45f9ddcc0eb5e0074c455e8ebb87c9
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 9e57c5f9a2bb433f182e7f7ce392f19985796cd56f8f40bed01bfed2e7385a25b4bf3fb7b06c541dae0b77cda2a981ac71d2a094d21f0beede0f8867b3fd1333
         
     | 
    
        data/CHANGELOG.md
    CHANGED
    
    | 
         @@ -1,5 +1,40 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # Change Log
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
      
 3 
     | 
    
         
            +
            ## 0.0.9
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            - Upgraded to glimmer gem v0.9.3
         
     | 
| 
      
 6 
     | 
    
         
            +
            - Fixed issue with missing Glimmer::Opal::ElementProxy#id=(value) method breaking Contact Manager sample Find feature
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            ## 0.0.8
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            - Contact Manager sample support
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            ## 0.0.7
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            - Tic Tac Toe sample support
         
     | 
| 
      
 15 
     | 
    
         
            +
            - Login sample support
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            ## 0.0.6
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            - Hello, Tab! sample support
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            ## 0.0.5
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            - Hello, Browser! sample support
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            ## 0.0.4
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            - Hello, List Single Selection! sample support
         
     | 
| 
      
 28 
     | 
    
         
            +
            - Hello, List Multi Selection! sample support
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
            ## 0.0.3
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
            - Hello, Computed! sample support
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
            ## 0.0.2
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
            - Hello, Combo! sample support
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
       3 
38 
     | 
    
         
             
            ## 0.0.1
         
     | 
| 
       4 
39 
     | 
    
         | 
| 
       5 
40 
     | 
    
         
             
            - Initial support for webifying Glimmer SWT apps
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -1,18 +1,20 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
             
     | 
| 
       2 
     | 
    
         
            -
            # <img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=65 /> Glimmer DSL for Opal 0.0.4 (Web GUI for Desktop Apps)
         
     | 
| 
      
 1 
     | 
    
         
            +
            # <img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=65 /> Glimmer DSL for Opal 0.0.9 (Webify Desktop Apps)
         
     | 
| 
       3 
2 
     | 
    
         
             
            [](http://badge.fury.io/rb/glimmer-dsl-opal)
         
     | 
| 
       4 
3 
     | 
    
         
             
            [](https://gitter.im/AndyObtiva/glimmer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
         
     | 
| 
       5 
4 
     | 
    
         | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
       8 
     | 
    
         
            -
            It enables running [Glimmer](https://github.com/AndyObtiva/glimmer) desktop apps on the web via [Rails](https://rubyonrails.org/) 5 and [Opal](https://opalrb.com/) 1.
         
     | 
| 
      
 5 
     | 
    
         
            +
            Glimmer DSL for Opal is an experimental web GUI adaptor for [Glimmer](https://github.com/AndyObtiva/glimmer) desktop apps (i.e. apps built with [Glimmer](https://github.com/AndyObtiva/glimmer) [DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt)). It webifies them via [Rails](https://rubyonrails.org/) and [Opal](https://opalrb.com/), allowing Ruby desktop apps to run on the web without changing a line of code. Apps may then be custom-styled for the web via standard CSS.
         
     | 
| 
       9 
6 
     | 
    
         | 
| 
       10 
     | 
    
         
            -
            NOTE: Alpha Version 0.0. 
     | 
| 
      
 7 
     | 
    
         
            +
            NOTE: Alpha Version 0.0.9 only supports bare-minimum capabilities for the following [glimmer-dsl-swt](https://github.com/AndyObtiva/glimmer-dsl-swt) [samples](https://github.com/AndyObtiva/glimmer#samples):
         
     | 
| 
       11 
8 
     | 
    
         
             
            - [Hello, World!](#hello-world)
         
     | 
| 
       12 
9 
     | 
    
         
             
            - [Hello, Combo!](#hello-combo)
         
     | 
| 
       13 
10 
     | 
    
         
             
            - [Hello, Computed!](#hello-computed)
         
     | 
| 
       14 
11 
     | 
    
         
             
            - [Hello, List Single Selection!](#hello-list-single-selection)
         
     | 
| 
       15 
12 
     | 
    
         
             
            - [Hello, List Multi Selection!](#hello-list-multi-selection)
         
     | 
| 
      
 13 
     | 
    
         
            +
            - [Hello, Browser!](#hello-browser)
         
     | 
| 
      
 14 
     | 
    
         
            +
            - [Hello, Tab!](#hello-tab)
         
     | 
| 
      
 15 
     | 
    
         
            +
            - [Login](#login)
         
     | 
| 
      
 16 
     | 
    
         
            +
            - [Tic Tac Toe](#tic-tac-toe)
         
     | 
| 
      
 17 
     | 
    
         
            +
            - [Contact Manager](#contact-manager)
         
     | 
| 
       16 
18 
     | 
    
         | 
| 
       17 
19 
     | 
    
         
             
            Other Glimmer DSL gems:
         
     | 
| 
       18 
20 
     | 
    
         
             
            - [glimmer-dsl-swt](https://github.com/AndyObtiva/glimmer-dsl-swt): Glimmer DSL for SWT (Desktop GUI)
         
     | 
| 
         @@ -30,6 +32,16 @@ The following keywords from [glimmer-dsl-swt](https://github.com/AndyObtiva/glim 
     | 
|
| 
       30 
32 
     | 
    
         
             
            - `text`
         
     | 
| 
       31 
33 
     | 
    
         
             
            - `composite`
         
     | 
| 
       32 
34 
     | 
    
         
             
            - `list` & `list(:multi)`
         
     | 
| 
      
 35 
     | 
    
         
            +
            - `tab_folder`
         
     | 
| 
      
 36 
     | 
    
         
            +
            - `tab_item`
         
     | 
| 
      
 37 
     | 
    
         
            +
            - `table`
         
     | 
| 
      
 38 
     | 
    
         
            +
            - `table_column`
         
     | 
| 
      
 39 
     | 
    
         
            +
            - `message_box`
         
     | 
| 
      
 40 
     | 
    
         
            +
            - `on_widget_selected`
         
     | 
| 
      
 41 
     | 
    
         
            +
            - `on_modify_text`
         
     | 
| 
      
 42 
     | 
    
         
            +
            - `observe`
         
     | 
| 
      
 43 
     | 
    
         
            +
            - `bind`
         
     | 
| 
      
 44 
     | 
    
         
            +
            - `async_exec`
         
     | 
| 
       33 
45 
     | 
    
         
             
            - `grid_layout`
         
     | 
| 
       34 
46 
     | 
    
         
             
            - `layout_data`
         
     | 
| 
       35 
47 
     | 
    
         | 
| 
         @@ -40,37 +52,55 @@ The following keywords from [glimmer-dsl-swt](https://github.com/AndyObtiva/glim 
     | 
|
| 
       40 
52 
     | 
    
         | 
| 
       41 
53 
     | 
    
         
             
            ## Setup
         
     | 
| 
       42 
54 
     | 
    
         | 
| 
       43 
     | 
    
         
            -
             
     | 
| 
      
 55 
     | 
    
         
            +
            (NOTE: if you run into issues, they are probably fixed in master or development/wip branch, you may check out instead)
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
            Please install a Rails 5 gem (e.g. `gem install rails -v5.2.4.3` )
         
     | 
| 
       44 
58 
     | 
    
         | 
| 
       45 
59 
     | 
    
         
             
            Start a new Rails 5 app:
         
     | 
| 
       46 
60 
     | 
    
         | 
| 
       47 
61 
     | 
    
         
             
            ```
         
     | 
| 
       48 
     | 
    
         
            -
            rails new  
     | 
| 
      
 62 
     | 
    
         
            +
            rails new glimmer_app
         
     | 
| 
       49 
63 
     | 
    
         
             
            ```
         
     | 
| 
       50 
64 
     | 
    
         | 
| 
       51 
     | 
    
         
            -
             
     | 
| 
      
 65 
     | 
    
         
            +
            Add the following to `Gemfile`:
         
     | 
| 
       52 
66 
     | 
    
         | 
| 
       53 
     | 
    
         
            -
            Add the following to `Gemfile` (NOTE: if you run into issues, they are probably fixed in master or development/wip branch, you may check out instead):
         
     | 
| 
       54 
67 
     | 
    
         
             
            ```
         
     | 
| 
       55 
     | 
    
         
            -
            gem 'opal-rails'
         
     | 
| 
       56 
     | 
    
         
            -
            gem 'opal- 
     | 
| 
       57 
     | 
    
         
            -
            gem ' 
     | 
| 
      
 68 
     | 
    
         
            +
            gem 'opal-rails', '~> 1.1.2'
         
     | 
| 
      
 69 
     | 
    
         
            +
            gem 'opal-async', '~> 1.1.0'
         
     | 
| 
      
 70 
     | 
    
         
            +
            gem 'opal-browser', '~> 0.2.0'
         
     | 
| 
      
 71 
     | 
    
         
            +
            gem 'glimmer-dsl-opal', '~> 0.0.9', require: false
         
     | 
| 
       58 
72 
     | 
    
         
             
            ```
         
     | 
| 
       59 
73 
     | 
    
         | 
| 
       60 
     | 
    
         
            -
             
     | 
| 
      
 74 
     | 
    
         
            +
            Follow (opal-rails)[https://github.com/opal/opal-rails] instructions, basically the configuration of: config/initializers/assets.rb
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
            Edit `config/initializers/assets.rb` and add the following at the bottom:
         
     | 
| 
       61 
77 
     | 
    
         
             
            ```
         
     | 
| 
       62 
78 
     | 
    
         
             
            Opal.use_gem 'glimmer-dsl-opal'
         
     | 
| 
       63 
79 
     | 
    
         
             
            ```
         
     | 
| 
       64 
80 
     | 
    
         | 
| 
       65 
     | 
    
         
            -
             
     | 
| 
      
 81 
     | 
    
         
            +
            Add the following line to the top of an empty `app/assets/javascripts/application.rb` (replacing `application.js`)
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 84 
     | 
    
         
            +
            require 'glimmer-dsl-opal' # brings opal and opal browser too
         
     | 
| 
      
 85 
     | 
    
         
            +
            ```
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
            Add more code to `app/assets/javascripts/application.rb` from one of the samples below or require a [Glimmer](https://github.com/AndyObtiva/glimmer) app/[custom-shell](https://github.com/AndyObtiva/glimmer#custom-shell-gem) gem.
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
            ## Samples
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
            ### Hello Samples
         
     | 
| 
       66 
92 
     | 
    
         | 
| 
       67 
     | 
    
         
            -
             
     | 
| 
      
 93 
     | 
    
         
            +
            #### Hello, World!
         
     | 
| 
       68 
94 
     | 
    
         | 
| 
       69 
     | 
    
         
            -
            Add the following  
     | 
| 
      
 95 
     | 
    
         
            +
            Add the following require statement to `app/assets/javascripts/application.rb`
         
     | 
| 
       70 
96 
     | 
    
         | 
| 
       71 
97 
     | 
    
         
             
            ```ruby
         
     | 
| 
       72 
     | 
    
         
            -
            require ' 
     | 
| 
      
 98 
     | 
    
         
            +
            require 'samples/hello/hello_world'
         
     | 
| 
      
 99 
     | 
    
         
            +
            ```
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
            Or add the Glimmer code directly if you prefer to play around with it:
         
     | 
| 
       73 
102 
     | 
    
         | 
| 
      
 103 
     | 
    
         
            +
            ```ruby
         
     | 
| 
       74 
104 
     | 
    
         
             
            include Glimmer
         
     | 
| 
       75 
105 
     | 
    
         | 
| 
       76 
106 
     | 
    
         
             
            shell {
         
     | 
| 
         @@ -78,12 +108,12 @@ shell { 
     | 
|
| 
       78 
108 
     | 
    
         
             
              label {
         
     | 
| 
       79 
109 
     | 
    
         
             
                text 'Hello, World!'
         
     | 
| 
       80 
110 
     | 
    
         
             
              }
         
     | 
| 
       81 
     | 
    
         
            -
            }
         
     | 
| 
      
 111 
     | 
    
         
            +
            }.open
         
     | 
| 
       82 
112 
     | 
    
         
             
            ```
         
     | 
| 
       83 
113 
     | 
    
         | 
| 
       84 
114 
     | 
    
         
             
            Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
         
     | 
| 
       85 
115 
     | 
    
         | 
| 
       86 
     | 
    
         
            -
            
         
     | 
| 
       87 
117 
     | 
    
         | 
| 
       88 
118 
     | 
    
         
             
            Glimmer app on the web (using `glimmer-dsl-opal` gem):
         
     | 
| 
       89 
119 
     | 
    
         | 
| 
         @@ -98,13 +128,17 @@ You should see "Hello, World!" 
     | 
|
| 
       98 
128 
     | 
    
         | 
| 
       99 
129 
     | 
    
         
             
            
         
     | 
| 
       100 
130 
     | 
    
         | 
| 
       101 
     | 
    
         
            -
             
     | 
| 
      
 131 
     | 
    
         
            +
            #### Hello, Combo!
         
     | 
| 
       102 
132 
     | 
    
         | 
| 
       103 
     | 
    
         
            -
            Add the following  
     | 
| 
      
 133 
     | 
    
         
            +
            Add the following require statement to `app/assets/javascripts/application.rb`
         
     | 
| 
       104 
134 
     | 
    
         | 
| 
       105 
135 
     | 
    
         
             
            ```ruby
         
     | 
| 
       106 
     | 
    
         
            -
            require ' 
     | 
| 
      
 136 
     | 
    
         
            +
            require 'samples/hello/hello_combo'
         
     | 
| 
      
 137 
     | 
    
         
            +
            ```
         
     | 
| 
      
 138 
     | 
    
         
            +
             
     | 
| 
      
 139 
     | 
    
         
            +
            Or add the Glimmer code directly if you prefer to play around with it:
         
     | 
| 
       107 
140 
     | 
    
         | 
| 
      
 141 
     | 
    
         
            +
            ```ruby
         
     | 
| 
       108 
142 
     | 
    
         
             
            class Person
         
     | 
| 
       109 
143 
     | 
    
         
             
              attr_accessor :country, :country_options
         
     | 
| 
       110 
144 
     | 
    
         | 
| 
         @@ -142,7 +176,7 @@ HelloCombo.new.launch 
     | 
|
| 
       142 
176 
     | 
    
         
             
            ```
         
     | 
| 
       143 
177 
     | 
    
         
             
            Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
         
     | 
| 
       144 
178 
     | 
    
         | 
| 
       145 
     | 
    
         
            -
            
         
     | 
| 
       146 
180 
     | 
    
         | 
| 
       147 
181 
     | 
    
         
             
            Glimmer app on the web (using `glimmer-dsl-opal` gem):
         
     | 
| 
       148 
182 
     | 
    
         | 
| 
         @@ -157,13 +191,18 @@ You should see "Hello, Combo!" 
     | 
|
| 
       157 
191 
     | 
    
         | 
| 
       158 
192 
     | 
    
         
             
            
         
     | 
| 
       159 
193 
     | 
    
         | 
| 
       160 
     | 
    
         
            -
             
     | 
| 
      
 194 
     | 
    
         
            +
            #### Hello, Computed!
         
     | 
| 
      
 195 
     | 
    
         
            +
             
     | 
| 
      
 196 
     | 
    
         
            +
            Add the following require statement to `app/assets/javascripts/application.rb`
         
     | 
| 
       161 
197 
     | 
    
         | 
| 
       162 
     | 
    
         
            -
            Add the following Glimmer code to `app/assets/javascripts/application.js.rb`
         
     | 
| 
       163 
198 
     | 
    
         | 
| 
       164 
199 
     | 
    
         
             
            ```ruby
         
     | 
| 
       165 
     | 
    
         
            -
            require ' 
     | 
| 
      
 200 
     | 
    
         
            +
            require 'samples/hello/hello_computed'
         
     | 
| 
      
 201 
     | 
    
         
            +
            ```
         
     | 
| 
      
 202 
     | 
    
         
            +
             
     | 
| 
      
 203 
     | 
    
         
            +
            Or add the Glimmer code directly if you prefer to play around with it:
         
     | 
| 
       166 
204 
     | 
    
         | 
| 
      
 205 
     | 
    
         
            +
            ```ruby
         
     | 
| 
       167 
206 
     | 
    
         
             
            class HelloComputed
         
     | 
| 
       168 
207 
     | 
    
         
             
              class Contact
         
     | 
| 
       169 
208 
     | 
    
         
             
                attr_accessor :first_name, :last_name, :year_of_birth
         
     | 
| 
         @@ -256,7 +295,7 @@ HelloComputed.new.launch 
     | 
|
| 
       256 
295 
     | 
    
         
             
            ```
         
     | 
| 
       257 
296 
     | 
    
         
             
            Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
         
     | 
| 
       258 
297 
     | 
    
         | 
| 
       259 
     | 
    
         
            -
            
         
     | 
| 
       260 
299 
     | 
    
         | 
| 
       261 
300 
     | 
    
         
             
            Glimmer app on the web (using `glimmer-dsl-opal` gem):
         
     | 
| 
       262 
301 
     | 
    
         | 
| 
         @@ -271,9 +310,16 @@ You should see "Hello, Computed!" 
     | 
|
| 
       271 
310 
     | 
    
         | 
| 
       272 
311 
     | 
    
         
             
            
         
     | 
| 
       273 
312 
     | 
    
         | 
| 
       274 
     | 
    
         
            -
             
     | 
| 
      
 313 
     | 
    
         
            +
            #### Hello, List Single Selection!
         
     | 
| 
      
 314 
     | 
    
         
            +
             
     | 
| 
      
 315 
     | 
    
         
            +
            Add the following require statement to `app/assets/javascripts/application.rb`
         
     | 
| 
       275 
316 
     | 
    
         | 
| 
       276 
     | 
    
         
            -
             
     | 
| 
      
 317 
     | 
    
         
            +
             
     | 
| 
      
 318 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 319 
     | 
    
         
            +
            require 'samples/hello/hello_list_single_selection'
         
     | 
| 
      
 320 
     | 
    
         
            +
            ```
         
     | 
| 
      
 321 
     | 
    
         
            +
             
     | 
| 
      
 322 
     | 
    
         
            +
            Or add the Glimmer code directly if you prefer to play around with it:
         
     | 
| 
       277 
323 
     | 
    
         | 
| 
       278 
324 
     | 
    
         
             
            ```ruby
         
     | 
| 
       279 
325 
     | 
    
         
             
            class Person 
         
     | 
| 
         @@ -313,7 +359,7 @@ HelloListSingleSelection.new.launch 
     | 
|
| 
       313 
359 
     | 
    
         
             
            ```
         
     | 
| 
       314 
360 
     | 
    
         
             
            Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
         
     | 
| 
       315 
361 
     | 
    
         | 
| 
       316 
     | 
    
         
            -
            
         
     | 
| 
       317 
363 
     | 
    
         | 
| 
       318 
364 
     | 
    
         
             
            Glimmer app on the web (using `glimmer-dsl-opal` gem):
         
     | 
| 
       319 
365 
     | 
    
         | 
| 
         @@ -328,9 +374,15 @@ You should see "Hello, List Single Selection!" 
     | 
|
| 
       328 
374 
     | 
    
         | 
| 
       329 
375 
     | 
    
         
             
            
         
     | 
| 
       330 
376 
     | 
    
         | 
| 
       331 
     | 
    
         
            -
             
     | 
| 
      
 377 
     | 
    
         
            +
            #### Hello, List Multi Selection!
         
     | 
| 
       332 
378 
     | 
    
         | 
| 
       333 
     | 
    
         
            -
            Add the following  
     | 
| 
      
 379 
     | 
    
         
            +
            Add the following require statement to `app/assets/javascripts/application.rb`
         
     | 
| 
      
 380 
     | 
    
         
            +
             
     | 
| 
      
 381 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 382 
     | 
    
         
            +
            require 'samples/hello/hello_list_multi_selection'
         
     | 
| 
      
 383 
     | 
    
         
            +
            ```
         
     | 
| 
      
 384 
     | 
    
         
            +
             
     | 
| 
      
 385 
     | 
    
         
            +
            Or add the Glimmer code directly if you prefer to play around with it:
         
     | 
| 
       334 
386 
     | 
    
         | 
| 
       335 
387 
     | 
    
         
             
            ```ruby
         
     | 
| 
       336 
388 
     | 
    
         
             
            class Person
         
     | 
| 
         @@ -380,7 +432,7 @@ HelloListMultiSelection.new.launch 
     | 
|
| 
       380 
432 
     | 
    
         
             
            ```
         
     | 
| 
       381 
433 
     | 
    
         
             
            Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
         
     | 
| 
       382 
434 
     | 
    
         | 
| 
       383 
     | 
    
         
            -
            
         
     | 
| 
       384 
436 
     | 
    
         | 
| 
       385 
437 
     | 
    
         
             
            Glimmer app on the web (using `glimmer-dsl-opal` gem):
         
     | 
| 
       386 
438 
     | 
    
         | 
| 
         @@ -395,6 +447,903 @@ You should see "Hello, List Multi Selection!" 
     | 
|
| 
       395 
447 
     | 
    
         | 
| 
       396 
448 
     | 
    
         
             
            
         
     | 
| 
       397 
449 
     | 
    
         | 
| 
      
 450 
     | 
    
         
            +
            #### Hello, Browser!
         
     | 
| 
      
 451 
     | 
    
         
            +
             
     | 
| 
      
 452 
     | 
    
         
            +
            Add the following require statement to `app/assets/javascripts/application.rb`
         
     | 
| 
      
 453 
     | 
    
         
            +
             
     | 
| 
      
 454 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 455 
     | 
    
         
            +
            require 'samples/hello/hello_browser'
         
     | 
| 
      
 456 
     | 
    
         
            +
            ```
         
     | 
| 
      
 457 
     | 
    
         
            +
             
     | 
| 
      
 458 
     | 
    
         
            +
            Or add the Glimmer code directly if you prefer to play around with it:
         
     | 
| 
      
 459 
     | 
    
         
            +
             
     | 
| 
      
 460 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 461 
     | 
    
         
            +
            include Glimmer
         
     | 
| 
      
 462 
     | 
    
         
            +
             
     | 
| 
      
 463 
     | 
    
         
            +
            shell {
         
     | 
| 
      
 464 
     | 
    
         
            +
              minimum_size 1024, 860
         
     | 
| 
      
 465 
     | 
    
         
            +
              browser {
         
     | 
| 
      
 466 
     | 
    
         
            +
                url 'http://brightonresort.com/about'
         
     | 
| 
      
 467 
     | 
    
         
            +
              }
         
     | 
| 
      
 468 
     | 
    
         
            +
            }.open
         
     | 
| 
      
 469 
     | 
    
         
            +
            ```
         
     | 
| 
      
 470 
     | 
    
         
            +
            Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
         
     | 
| 
      
 471 
     | 
    
         
            +
             
     | 
| 
      
 472 
     | 
    
         
            +
            
         
     | 
| 
      
 473 
     | 
    
         
            +
             
     | 
| 
      
 474 
     | 
    
         
            +
            Glimmer app on the web (using `glimmer-dsl-opal` gem):
         
     | 
| 
      
 475 
     | 
    
         
            +
             
     | 
| 
      
 476 
     | 
    
         
            +
            Start the Rails server:
         
     | 
| 
      
 477 
     | 
    
         
            +
            ```
         
     | 
| 
      
 478 
     | 
    
         
            +
            rails s
         
     | 
| 
      
 479 
     | 
    
         
            +
            ```
         
     | 
| 
      
 480 
     | 
    
         
            +
             
     | 
| 
      
 481 
     | 
    
         
            +
            Visit `http://localhost:3000`
         
     | 
| 
      
 482 
     | 
    
         
            +
             
     | 
| 
      
 483 
     | 
    
         
            +
            You should see "Hello, Browser!"
         
     | 
| 
      
 484 
     | 
    
         
            +
             
     | 
| 
      
 485 
     | 
    
         
            +
            
         
     | 
| 
      
 486 
     | 
    
         
            +
             
     | 
| 
      
 487 
     | 
    
         
            +
            #### Hello, Tab!
         
     | 
| 
      
 488 
     | 
    
         
            +
             
     | 
| 
      
 489 
     | 
    
         
            +
            Add the following require statement to `app/assets/javascripts/application.rb`
         
     | 
| 
      
 490 
     | 
    
         
            +
             
     | 
| 
      
 491 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 492 
     | 
    
         
            +
            require 'samples/hello/hello_tab'
         
     | 
| 
      
 493 
     | 
    
         
            +
            ```
         
     | 
| 
      
 494 
     | 
    
         
            +
             
     | 
| 
      
 495 
     | 
    
         
            +
            Or add the Glimmer code directly if you prefer to play around with it:
         
     | 
| 
      
 496 
     | 
    
         
            +
             
     | 
| 
      
 497 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 498 
     | 
    
         
            +
            class HelloTab
         
     | 
| 
      
 499 
     | 
    
         
            +
              include Glimmer
         
     | 
| 
      
 500 
     | 
    
         
            +
              def launch
         
     | 
| 
      
 501 
     | 
    
         
            +
                shell {
         
     | 
| 
      
 502 
     | 
    
         
            +
                  text "Hello, Tab!"
         
     | 
| 
      
 503 
     | 
    
         
            +
                  tab_folder {
         
     | 
| 
      
 504 
     | 
    
         
            +
                    tab_item {
         
     | 
| 
      
 505 
     | 
    
         
            +
                      text "English"
         
     | 
| 
      
 506 
     | 
    
         
            +
                      label {
         
     | 
| 
      
 507 
     | 
    
         
            +
                        text "Hello, World!"
         
     | 
| 
      
 508 
     | 
    
         
            +
                      }
         
     | 
| 
      
 509 
     | 
    
         
            +
                    }
         
     | 
| 
      
 510 
     | 
    
         
            +
                    tab_item {
         
     | 
| 
      
 511 
     | 
    
         
            +
                      text "French"
         
     | 
| 
      
 512 
     | 
    
         
            +
                      label {
         
     | 
| 
      
 513 
     | 
    
         
            +
                        text "Bonjour, Univers!"
         
     | 
| 
      
 514 
     | 
    
         
            +
                      }
         
     | 
| 
      
 515 
     | 
    
         
            +
                    }
         
     | 
| 
      
 516 
     | 
    
         
            +
                  }
         
     | 
| 
      
 517 
     | 
    
         
            +
                }.open
         
     | 
| 
      
 518 
     | 
    
         
            +
              end
         
     | 
| 
      
 519 
     | 
    
         
            +
            end
         
     | 
| 
      
 520 
     | 
    
         
            +
             
     | 
| 
      
 521 
     | 
    
         
            +
            HelloTab.new.launch
         
     | 
| 
      
 522 
     | 
    
         
            +
            ```
         
     | 
| 
      
 523 
     | 
    
         
            +
            Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
         
     | 
| 
      
 524 
     | 
    
         
            +
             
     | 
| 
      
 525 
     | 
    
         
            +
            
         
     | 
| 
      
 526 
     | 
    
         
            +
            
         
     | 
| 
      
 527 
     | 
    
         
            +
             
     | 
| 
      
 528 
     | 
    
         
            +
            Glimmer app on the web (using `glimmer-dsl-opal` gem):
         
     | 
| 
      
 529 
     | 
    
         
            +
             
     | 
| 
      
 530 
     | 
    
         
            +
            Start the Rails server:
         
     | 
| 
      
 531 
     | 
    
         
            +
            ```
         
     | 
| 
      
 532 
     | 
    
         
            +
            rails s
         
     | 
| 
      
 533 
     | 
    
         
            +
            ```
         
     | 
| 
      
 534 
     | 
    
         
            +
             
     | 
| 
      
 535 
     | 
    
         
            +
            Visit `http://localhost:3000`
         
     | 
| 
      
 536 
     | 
    
         
            +
             
     | 
| 
      
 537 
     | 
    
         
            +
            You should see "Hello, Tab!"
         
     | 
| 
      
 538 
     | 
    
         
            +
             
     | 
| 
      
 539 
     | 
    
         
            +
            
         
     | 
| 
      
 540 
     | 
    
         
            +
            
         
     | 
| 
      
 541 
     | 
    
         
            +
             
     | 
| 
      
 542 
     | 
    
         
            +
            ### Elaborate Samples
         
     | 
| 
      
 543 
     | 
    
         
            +
             
     | 
| 
      
 544 
     | 
    
         
            +
            #### Login
         
     | 
| 
      
 545 
     | 
    
         
            +
             
     | 
| 
      
 546 
     | 
    
         
            +
            Add the following require statement to `app/assets/javascripts/application.rb`
         
     | 
| 
      
 547 
     | 
    
         
            +
             
     | 
| 
      
 548 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 549 
     | 
    
         
            +
            require 'samples/elaborate/login'
         
     | 
| 
      
 550 
     | 
    
         
            +
            ```
         
     | 
| 
      
 551 
     | 
    
         
            +
             
     | 
| 
      
 552 
     | 
    
         
            +
            Or add the Glimmer code directly if you prefer to play around with it:
         
     | 
| 
      
 553 
     | 
    
         
            +
             
     | 
| 
      
 554 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 555 
     | 
    
         
            +
            require "observer"
         
     | 
| 
      
 556 
     | 
    
         
            +
             
     | 
| 
      
 557 
     | 
    
         
            +
            #Presents login screen data
         
     | 
| 
      
 558 
     | 
    
         
            +
            class LoginPresenter
         
     | 
| 
      
 559 
     | 
    
         
            +
             
     | 
| 
      
 560 
     | 
    
         
            +
              attr_accessor :user_name
         
     | 
| 
      
 561 
     | 
    
         
            +
              attr_accessor :password
         
     | 
| 
      
 562 
     | 
    
         
            +
              attr_accessor :status
         
     | 
| 
      
 563 
     | 
    
         
            +
             
     | 
| 
      
 564 
     | 
    
         
            +
              def initialize
         
     | 
| 
      
 565 
     | 
    
         
            +
                @user_name = ""
         
     | 
| 
      
 566 
     | 
    
         
            +
                @password = ""
         
     | 
| 
      
 567 
     | 
    
         
            +
                @status = "Logged Out"
         
     | 
| 
      
 568 
     | 
    
         
            +
              end
         
     | 
| 
      
 569 
     | 
    
         
            +
             
     | 
| 
      
 570 
     | 
    
         
            +
              def status=(status)
         
     | 
| 
      
 571 
     | 
    
         
            +
                @status = status
         
     | 
| 
      
 572 
     | 
    
         
            +
             
     | 
| 
      
 573 
     | 
    
         
            +
                #TODO add feature to bind dependent properties to master property (2017-07-25 nested data binding)
         
     | 
| 
      
 574 
     | 
    
         
            +
                notify_observers("logged_in")
         
     | 
| 
      
 575 
     | 
    
         
            +
                notify_observers("logged_out")
         
     | 
| 
      
 576 
     | 
    
         
            +
              end
         
     | 
| 
      
 577 
     | 
    
         
            +
             
     | 
| 
      
 578 
     | 
    
         
            +
              def logged_in
         
     | 
| 
      
 579 
     | 
    
         
            +
                self.status == "Logged In"
         
     | 
| 
      
 580 
     | 
    
         
            +
              end
         
     | 
| 
      
 581 
     | 
    
         
            +
             
     | 
| 
      
 582 
     | 
    
         
            +
              def logged_out
         
     | 
| 
      
 583 
     | 
    
         
            +
                !self.logged_in
         
     | 
| 
      
 584 
     | 
    
         
            +
              end
         
     | 
| 
      
 585 
     | 
    
         
            +
             
     | 
| 
      
 586 
     | 
    
         
            +
              def login
         
     | 
| 
      
 587 
     | 
    
         
            +
                self.status = "Logged In"
         
     | 
| 
      
 588 
     | 
    
         
            +
              end
         
     | 
| 
      
 589 
     | 
    
         
            +
             
     | 
| 
      
 590 
     | 
    
         
            +
              def logout
         
     | 
| 
      
 591 
     | 
    
         
            +
                self.user_name = ""
         
     | 
| 
      
 592 
     | 
    
         
            +
                self.password = ""
         
     | 
| 
      
 593 
     | 
    
         
            +
                self.status = "Logged Out"
         
     | 
| 
      
 594 
     | 
    
         
            +
              end
         
     | 
| 
      
 595 
     | 
    
         
            +
             
     | 
| 
      
 596 
     | 
    
         
            +
            end
         
     | 
| 
      
 597 
     | 
    
         
            +
             
     | 
| 
      
 598 
     | 
    
         
            +
            #Login screen
         
     | 
| 
      
 599 
     | 
    
         
            +
            class Login
         
     | 
| 
      
 600 
     | 
    
         
            +
              include Glimmer
         
     | 
| 
      
 601 
     | 
    
         
            +
             
     | 
| 
      
 602 
     | 
    
         
            +
              def launch
         
     | 
| 
      
 603 
     | 
    
         
            +
                presenter = LoginPresenter.new
         
     | 
| 
      
 604 
     | 
    
         
            +
                @shell = shell {
         
     | 
| 
      
 605 
     | 
    
         
            +
                  text "Login"
         
     | 
| 
      
 606 
     | 
    
         
            +
                  composite {
         
     | 
| 
      
 607 
     | 
    
         
            +
                    grid_layout 2, false #two columns with differing widths
         
     | 
| 
      
 608 
     | 
    
         
            +
             
     | 
| 
      
 609 
     | 
    
         
            +
                    label { text "Username:" } # goes in column 1
         
     | 
| 
      
 610 
     | 
    
         
            +
                    text {                     # goes in column 2
         
     | 
| 
      
 611 
     | 
    
         
            +
                      text bind(presenter, :user_name)
         
     | 
| 
      
 612 
     | 
    
         
            +
                      enabled bind(presenter, :logged_out)
         
     | 
| 
      
 613 
     | 
    
         
            +
                    }
         
     | 
| 
      
 614 
     | 
    
         
            +
             
     | 
| 
      
 615 
     | 
    
         
            +
                    label { text "Password:" }
         
     | 
| 
      
 616 
     | 
    
         
            +
                    text(:password, :border) {
         
     | 
| 
      
 617 
     | 
    
         
            +
                      text bind(presenter, :password)
         
     | 
| 
      
 618 
     | 
    
         
            +
                      enabled bind(presenter, :logged_out)
         
     | 
| 
      
 619 
     | 
    
         
            +
                    }
         
     | 
| 
      
 620 
     | 
    
         
            +
             
     | 
| 
      
 621 
     | 
    
         
            +
                    label { text "Status:" }
         
     | 
| 
      
 622 
     | 
    
         
            +
                    label { text bind(presenter, :status) }
         
     | 
| 
      
 623 
     | 
    
         
            +
             
     | 
| 
      
 624 
     | 
    
         
            +
                    button {
         
     | 
| 
      
 625 
     | 
    
         
            +
                      text "Login"
         
     | 
| 
      
 626 
     | 
    
         
            +
                      enabled bind(presenter, :logged_out)
         
     | 
| 
      
 627 
     | 
    
         
            +
                      on_widget_selected { presenter.login }
         
     | 
| 
      
 628 
     | 
    
         
            +
                    }
         
     | 
| 
      
 629 
     | 
    
         
            +
             
     | 
| 
      
 630 
     | 
    
         
            +
                    button {
         
     | 
| 
      
 631 
     | 
    
         
            +
                      text "Logout"
         
     | 
| 
      
 632 
     | 
    
         
            +
                      enabled bind(presenter, :logged_in)
         
     | 
| 
      
 633 
     | 
    
         
            +
                      on_widget_selected { presenter.logout }
         
     | 
| 
      
 634 
     | 
    
         
            +
                    }
         
     | 
| 
      
 635 
     | 
    
         
            +
                  }
         
     | 
| 
      
 636 
     | 
    
         
            +
                }
         
     | 
| 
      
 637 
     | 
    
         
            +
                @shell.open
         
     | 
| 
      
 638 
     | 
    
         
            +
              end
         
     | 
| 
      
 639 
     | 
    
         
            +
            end
         
     | 
| 
      
 640 
     | 
    
         
            +
             
     | 
| 
      
 641 
     | 
    
         
            +
            Login.new.launch
         
     | 
| 
      
 642 
     | 
    
         
            +
            ```
         
     | 
| 
      
 643 
     | 
    
         
            +
            Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
         
     | 
| 
      
 644 
     | 
    
         
            +
             
     | 
| 
      
 645 
     | 
    
         
            +
            
         
     | 
| 
      
 646 
     | 
    
         
            +
            
         
     | 
| 
      
 647 
     | 
    
         
            +
            
         
     | 
| 
      
 648 
     | 
    
         
            +
             
     | 
| 
      
 649 
     | 
    
         
            +
            Glimmer app on the web (using `glimmer-dsl-opal` gem):
         
     | 
| 
      
 650 
     | 
    
         
            +
             
     | 
| 
      
 651 
     | 
    
         
            +
            Start the Rails server:
         
     | 
| 
      
 652 
     | 
    
         
            +
            ```
         
     | 
| 
      
 653 
     | 
    
         
            +
            rails s
         
     | 
| 
      
 654 
     | 
    
         
            +
            ```
         
     | 
| 
      
 655 
     | 
    
         
            +
             
     | 
| 
      
 656 
     | 
    
         
            +
            Visit `http://localhost:3000`
         
     | 
| 
      
 657 
     | 
    
         
            +
             
     | 
| 
      
 658 
     | 
    
         
            +
            You should see "Login" dialog
         
     | 
| 
      
 659 
     | 
    
         
            +
             
     | 
| 
      
 660 
     | 
    
         
            +
            
         
     | 
| 
      
 661 
     | 
    
         
            +
            
         
     | 
| 
      
 662 
     | 
    
         
            +
            
         
     | 
| 
      
 663 
     | 
    
         
            +
             
     | 
| 
      
 664 
     | 
    
         
            +
            #### Tic Tac Toe
         
     | 
| 
      
 665 
     | 
    
         
            +
             
     | 
| 
      
 666 
     | 
    
         
            +
            Add the following require statement to `app/assets/javascripts/application.rb`
         
     | 
| 
      
 667 
     | 
    
         
            +
             
     | 
| 
      
 668 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 669 
     | 
    
         
            +
            require 'samples/elaborate/tic_tac_toe'
         
     | 
| 
      
 670 
     | 
    
         
            +
            ```
         
     | 
| 
      
 671 
     | 
    
         
            +
             
     | 
| 
      
 672 
     | 
    
         
            +
            Or add the Glimmer code directly if you prefer to play around with it:
         
     | 
| 
      
 673 
     | 
    
         
            +
             
     | 
| 
      
 674 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 675 
     | 
    
         
            +
            class TicTacToe
         
     | 
| 
      
 676 
     | 
    
         
            +
              class Cell
         
     | 
| 
      
 677 
     | 
    
         
            +
                EMPTY = ""
         
     | 
| 
      
 678 
     | 
    
         
            +
                attr_accessor :sign, :empty
         
     | 
| 
      
 679 
     | 
    
         
            +
              
         
     | 
| 
      
 680 
     | 
    
         
            +
                def initialize
         
     | 
| 
      
 681 
     | 
    
         
            +
                  reset
         
     | 
| 
      
 682 
     | 
    
         
            +
                end
         
     | 
| 
      
 683 
     | 
    
         
            +
              
         
     | 
| 
      
 684 
     | 
    
         
            +
                def mark(sign)
         
     | 
| 
      
 685 
     | 
    
         
            +
                  self.sign = sign
         
     | 
| 
      
 686 
     | 
    
         
            +
                end
         
     | 
| 
      
 687 
     | 
    
         
            +
              
         
     | 
| 
      
 688 
     | 
    
         
            +
                def reset
         
     | 
| 
      
 689 
     | 
    
         
            +
                  self.sign = EMPTY
         
     | 
| 
      
 690 
     | 
    
         
            +
                end
         
     | 
| 
      
 691 
     | 
    
         
            +
              
         
     | 
| 
      
 692 
     | 
    
         
            +
                def sign=(sign_symbol)
         
     | 
| 
      
 693 
     | 
    
         
            +
                  @sign = sign_symbol
         
     | 
| 
      
 694 
     | 
    
         
            +
                  self.empty = sign == EMPTY
         
     | 
| 
      
 695 
     | 
    
         
            +
                end
         
     | 
| 
      
 696 
     | 
    
         
            +
              
         
     | 
| 
      
 697 
     | 
    
         
            +
                def marked
         
     | 
| 
      
 698 
     | 
    
         
            +
                  !empty
         
     | 
| 
      
 699 
     | 
    
         
            +
                end
         
     | 
| 
      
 700 
     | 
    
         
            +
              end
         
     | 
| 
      
 701 
     | 
    
         
            +
            end
         
     | 
| 
      
 702 
     | 
    
         
            +
             
     | 
| 
      
 703 
     | 
    
         
            +
            class TicTacToe
         
     | 
| 
      
 704 
     | 
    
         
            +
              class Board
         
     | 
| 
      
 705 
     | 
    
         
            +
                DRAW = :draw
         
     | 
| 
      
 706 
     | 
    
         
            +
                IN_PROGRESS = :in_progress
         
     | 
| 
      
 707 
     | 
    
         
            +
                WIN = :win
         
     | 
| 
      
 708 
     | 
    
         
            +
                attr :winning_sign
         
     | 
| 
      
 709 
     | 
    
         
            +
                attr_accessor :game_status
         
     | 
| 
      
 710 
     | 
    
         
            +
              
         
     | 
| 
      
 711 
     | 
    
         
            +
                def initialize
         
     | 
| 
      
 712 
     | 
    
         
            +
                  @sign_state_machine = {nil => "X", "X" => "O", "O" => "X"}
         
     | 
| 
      
 713 
     | 
    
         
            +
                  build_grid
         
     | 
| 
      
 714 
     | 
    
         
            +
                  @winning_sign = Cell::EMPTY
         
     | 
| 
      
 715 
     | 
    
         
            +
                  @game_status = IN_PROGRESS
         
     | 
| 
      
 716 
     | 
    
         
            +
                end
         
     | 
| 
      
 717 
     | 
    
         
            +
              
         
     | 
| 
      
 718 
     | 
    
         
            +
                #row and column numbers are 1-based
         
     | 
| 
      
 719 
     | 
    
         
            +
                def mark(row, column)
         
     | 
| 
      
 720 
     | 
    
         
            +
                  self[row, column].mark(current_sign)
         
     | 
| 
      
 721 
     | 
    
         
            +
                  game_over? #updates winning sign
         
     | 
| 
      
 722 
     | 
    
         
            +
                end
         
     | 
| 
      
 723 
     | 
    
         
            +
              
         
     | 
| 
      
 724 
     | 
    
         
            +
                def current_sign
         
     | 
| 
      
 725 
     | 
    
         
            +
                  @current_sign = @sign_state_machine[@current_sign]
         
     | 
| 
      
 726 
     | 
    
         
            +
                end
         
     | 
| 
      
 727 
     | 
    
         
            +
              
         
     | 
| 
      
 728 
     | 
    
         
            +
                def [](row, column)
         
     | 
| 
      
 729 
     | 
    
         
            +
                  @grid[row-1][column-1]
         
     | 
| 
      
 730 
     | 
    
         
            +
                end
         
     | 
| 
      
 731 
     | 
    
         
            +
              
         
     | 
| 
      
 732 
     | 
    
         
            +
                def game_over?
         
     | 
| 
      
 733 
     | 
    
         
            +
                   win? or draw?
         
     | 
| 
      
 734 
     | 
    
         
            +
                end
         
     | 
| 
      
 735 
     | 
    
         
            +
              
         
     | 
| 
      
 736 
     | 
    
         
            +
                def win?
         
     | 
| 
      
 737 
     | 
    
         
            +
                  win = (row_win? or column_win? or diagonal_win?)
         
     | 
| 
      
 738 
     | 
    
         
            +
                  self.game_status=WIN if win
         
     | 
| 
      
 739 
     | 
    
         
            +
                  win
         
     | 
| 
      
 740 
     | 
    
         
            +
                end
         
     | 
| 
      
 741 
     | 
    
         
            +
              
         
     | 
| 
      
 742 
     | 
    
         
            +
                def reset
         
     | 
| 
      
 743 
     | 
    
         
            +
                  (1..3).each do |row|
         
     | 
| 
      
 744 
     | 
    
         
            +
                    (1..3).each do |column|
         
     | 
| 
      
 745 
     | 
    
         
            +
                      self[row, column].reset
         
     | 
| 
      
 746 
     | 
    
         
            +
                    end
         
     | 
| 
      
 747 
     | 
    
         
            +
                  end
         
     | 
| 
      
 748 
     | 
    
         
            +
                  @winning_sign = Cell::EMPTY
         
     | 
| 
      
 749 
     | 
    
         
            +
                  @current_sign = nil
         
     | 
| 
      
 750 
     | 
    
         
            +
                  self.game_status=IN_PROGRESS
         
     | 
| 
      
 751 
     | 
    
         
            +
                end
         
     | 
| 
      
 752 
     | 
    
         
            +
              
         
     | 
| 
      
 753 
     | 
    
         
            +
                private
         
     | 
| 
      
 754 
     | 
    
         
            +
              
         
     | 
| 
      
 755 
     | 
    
         
            +
                def build_grid
         
     | 
| 
      
 756 
     | 
    
         
            +
                  @grid = []
         
     | 
| 
      
 757 
     | 
    
         
            +
                  3.times do |row_index| #0-based
         
     | 
| 
      
 758 
     | 
    
         
            +
                    @grid << []
         
     | 
| 
      
 759 
     | 
    
         
            +
                    3.times { @grid[row_index] << Cell.new }
         
     | 
| 
      
 760 
     | 
    
         
            +
                  end
         
     | 
| 
      
 761 
     | 
    
         
            +
                end
         
     | 
| 
      
 762 
     | 
    
         
            +
              
         
     | 
| 
      
 763 
     | 
    
         
            +
                def row_win?
         
     | 
| 
      
 764 
     | 
    
         
            +
                  (1..3).each do |row|
         
     | 
| 
      
 765 
     | 
    
         
            +
                    if row_has_same_sign(row)
         
     | 
| 
      
 766 
     | 
    
         
            +
                      @winning_sign = self[row, 1].sign
         
     | 
| 
      
 767 
     | 
    
         
            +
                      return true
         
     | 
| 
      
 768 
     | 
    
         
            +
                    end
         
     | 
| 
      
 769 
     | 
    
         
            +
                  end
         
     | 
| 
      
 770 
     | 
    
         
            +
                  false
         
     | 
| 
      
 771 
     | 
    
         
            +
                end
         
     | 
| 
      
 772 
     | 
    
         
            +
              
         
     | 
| 
      
 773 
     | 
    
         
            +
                def column_win?
         
     | 
| 
      
 774 
     | 
    
         
            +
                  (1..3).each do |column|
         
     | 
| 
      
 775 
     | 
    
         
            +
                    if column_has_same_sign(column)
         
     | 
| 
      
 776 
     | 
    
         
            +
                      @winning_sign = self[1, column].sign
         
     | 
| 
      
 777 
     | 
    
         
            +
                      return true
         
     | 
| 
      
 778 
     | 
    
         
            +
                    end
         
     | 
| 
      
 779 
     | 
    
         
            +
                  end
         
     | 
| 
      
 780 
     | 
    
         
            +
                  false
         
     | 
| 
      
 781 
     | 
    
         
            +
                end
         
     | 
| 
      
 782 
     | 
    
         
            +
              
         
     | 
| 
      
 783 
     | 
    
         
            +
                #needs refactoring if we ever decide to make the board size dynamic
         
     | 
| 
      
 784 
     | 
    
         
            +
                def diagonal_win?
         
     | 
| 
      
 785 
     | 
    
         
            +
                  if (self[1, 1].sign == self[2, 2].sign) and (self[2, 2].sign == self[3, 3].sign) and self[1, 1].marked
         
     | 
| 
      
 786 
     | 
    
         
            +
                    @winning_sign = self[1, 1].sign
         
     | 
| 
      
 787 
     | 
    
         
            +
                    return true
         
     | 
| 
      
 788 
     | 
    
         
            +
                  end
         
     | 
| 
      
 789 
     | 
    
         
            +
                  if (self[3, 1].sign == self[2, 2].sign) and (self[2, 2].sign == self[1, 3].sign) and self[3, 1].marked
         
     | 
| 
      
 790 
     | 
    
         
            +
                    @winning_sign = self[3, 1].sign
         
     | 
| 
      
 791 
     | 
    
         
            +
                    return true
         
     | 
| 
      
 792 
     | 
    
         
            +
                  end
         
     | 
| 
      
 793 
     | 
    
         
            +
                  false
         
     | 
| 
      
 794 
     | 
    
         
            +
                end
         
     | 
| 
      
 795 
     | 
    
         
            +
              
         
     | 
| 
      
 796 
     | 
    
         
            +
                def draw?
         
     | 
| 
      
 797 
     | 
    
         
            +
                  @board_full = true
         
     | 
| 
      
 798 
     | 
    
         
            +
                  3.times do |x|
         
     | 
| 
      
 799 
     | 
    
         
            +
                    3.times do |y|
         
     | 
| 
      
 800 
     | 
    
         
            +
                      @board_full = false if self[x, y].empty
         
     | 
| 
      
 801 
     | 
    
         
            +
                    end
         
     | 
| 
      
 802 
     | 
    
         
            +
                  end
         
     | 
| 
      
 803 
     | 
    
         
            +
                  self.game_status = DRAW if @board_full
         
     | 
| 
      
 804 
     | 
    
         
            +
                  @board_full
         
     | 
| 
      
 805 
     | 
    
         
            +
                end
         
     | 
| 
      
 806 
     | 
    
         
            +
              
         
     | 
| 
      
 807 
     | 
    
         
            +
                def row_has_same_sign(number)
         
     | 
| 
      
 808 
     | 
    
         
            +
                  row_sign = self[number, 1].sign
         
     | 
| 
      
 809 
     | 
    
         
            +
                  [2, 3].each do |column|
         
     | 
| 
      
 810 
     | 
    
         
            +
                    return false unless row_sign == (self[number, column].sign)
         
     | 
| 
      
 811 
     | 
    
         
            +
                  end
         
     | 
| 
      
 812 
     | 
    
         
            +
                  true if self[number, 1].marked
         
     | 
| 
      
 813 
     | 
    
         
            +
                end
         
     | 
| 
      
 814 
     | 
    
         
            +
              
         
     | 
| 
      
 815 
     | 
    
         
            +
                def column_has_same_sign(number)
         
     | 
| 
      
 816 
     | 
    
         
            +
                  column_sign = self[1, number].sign
         
     | 
| 
      
 817 
     | 
    
         
            +
                  [2, 3].each do |row|
         
     | 
| 
      
 818 
     | 
    
         
            +
                    return false unless column_sign == (self[row, number].sign)
         
     | 
| 
      
 819 
     | 
    
         
            +
                  end
         
     | 
| 
      
 820 
     | 
    
         
            +
                  true if self[1, number].marked
         
     | 
| 
      
 821 
     | 
    
         
            +
                end
         
     | 
| 
      
 822 
     | 
    
         
            +
              
         
     | 
| 
      
 823 
     | 
    
         
            +
              end
         
     | 
| 
      
 824 
     | 
    
         
            +
            end
         
     | 
| 
      
 825 
     | 
    
         
            +
             
     | 
| 
      
 826 
     | 
    
         
            +
            class TicTacToe
         
     | 
| 
      
 827 
     | 
    
         
            +
              include Glimmer
         
     | 
| 
      
 828 
     | 
    
         
            +
             
     | 
| 
      
 829 
     | 
    
         
            +
              def initialize
         
     | 
| 
      
 830 
     | 
    
         
            +
                @tic_tac_toe_board = Board.new
         
     | 
| 
      
 831 
     | 
    
         
            +
                @shell = shell {
         
     | 
| 
      
 832 
     | 
    
         
            +
                  text "Tic-Tac-Toe"
         
     | 
| 
      
 833 
     | 
    
         
            +
                  composite {
         
     | 
| 
      
 834 
     | 
    
         
            +
                    grid_layout 3, true
         
     | 
| 
      
 835 
     | 
    
         
            +
                    (1..3).each { |row|
         
     | 
| 
      
 836 
     | 
    
         
            +
                      (1..3).each { |column|
         
     | 
| 
      
 837 
     | 
    
         
            +
                        button {
         
     | 
| 
      
 838 
     | 
    
         
            +
                          layout_data :fill, :fill, true, true
         
     | 
| 
      
 839 
     | 
    
         
            +
                          text        bind(@tic_tac_toe_board[row, column], :sign)
         
     | 
| 
      
 840 
     | 
    
         
            +
                          enabled     bind(@tic_tac_toe_board[row, column], :empty)
         
     | 
| 
      
 841 
     | 
    
         
            +
                          on_widget_selected {
         
     | 
| 
      
 842 
     | 
    
         
            +
                            @tic_tac_toe_board.mark(row, column)
         
     | 
| 
      
 843 
     | 
    
         
            +
                          }
         
     | 
| 
      
 844 
     | 
    
         
            +
                        }
         
     | 
| 
      
 845 
     | 
    
         
            +
                      }
         
     | 
| 
      
 846 
     | 
    
         
            +
                    }
         
     | 
| 
      
 847 
     | 
    
         
            +
                  }
         
     | 
| 
      
 848 
     | 
    
         
            +
                }
         
     | 
| 
      
 849 
     | 
    
         
            +
                observe(@tic_tac_toe_board, :game_status) { |game_status|
         
     | 
| 
      
 850 
     | 
    
         
            +
                  display_win_message if game_status == Board::WIN
         
     | 
| 
      
 851 
     | 
    
         
            +
                  display_draw_message if game_status == Board::DRAW
         
     | 
| 
      
 852 
     | 
    
         
            +
                }
         
     | 
| 
      
 853 
     | 
    
         
            +
              end
         
     | 
| 
      
 854 
     | 
    
         
            +
             
     | 
| 
      
 855 
     | 
    
         
            +
              def display_win_message
         
     | 
| 
      
 856 
     | 
    
         
            +
                display_game_over_message("Player #{@tic_tac_toe_board.winning_sign} has won!")
         
     | 
| 
      
 857 
     | 
    
         
            +
              end
         
     | 
| 
      
 858 
     | 
    
         
            +
             
     | 
| 
      
 859 
     | 
    
         
            +
              def display_draw_message
         
     | 
| 
      
 860 
     | 
    
         
            +
                display_game_over_message("Draw!")
         
     | 
| 
      
 861 
     | 
    
         
            +
              end
         
     | 
| 
      
 862 
     | 
    
         
            +
             
     | 
| 
      
 863 
     | 
    
         
            +
              def display_game_over_message(message_text)
         
     | 
| 
      
 864 
     | 
    
         
            +
                message_box(@shell) {
         
     | 
| 
      
 865 
     | 
    
         
            +
                  text 'Game Over'
         
     | 
| 
      
 866 
     | 
    
         
            +
                  message message_text
         
     | 
| 
      
 867 
     | 
    
         
            +
                }.open
         
     | 
| 
      
 868 
     | 
    
         
            +
                @tic_tac_toe_board.reset
         
     | 
| 
      
 869 
     | 
    
         
            +
              end
         
     | 
| 
      
 870 
     | 
    
         
            +
             
     | 
| 
      
 871 
     | 
    
         
            +
              def open
         
     | 
| 
      
 872 
     | 
    
         
            +
                @shell.open
         
     | 
| 
      
 873 
     | 
    
         
            +
              end
         
     | 
| 
      
 874 
     | 
    
         
            +
            end
         
     | 
| 
      
 875 
     | 
    
         
            +
             
     | 
| 
      
 876 
     | 
    
         
            +
            TicTacToe.new.open
         
     | 
| 
      
 877 
     | 
    
         
            +
            ```
         
     | 
| 
      
 878 
     | 
    
         
            +
            Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
         
     | 
| 
      
 879 
     | 
    
         
            +
             
     | 
| 
      
 880 
     | 
    
         
            +
            
         
     | 
| 
      
 881 
     | 
    
         
            +
            
         
     | 
| 
      
 882 
     | 
    
         
            +
            
         
     | 
| 
      
 883 
     | 
    
         
            +
             
     | 
| 
      
 884 
     | 
    
         
            +
            Glimmer app on the web (using `glimmer-dsl-opal` gem):
         
     | 
| 
      
 885 
     | 
    
         
            +
             
     | 
| 
      
 886 
     | 
    
         
            +
            Start the Rails server:
         
     | 
| 
      
 887 
     | 
    
         
            +
            ```
         
     | 
| 
      
 888 
     | 
    
         
            +
            rails s
         
     | 
| 
      
 889 
     | 
    
         
            +
            ```
         
     | 
| 
      
 890 
     | 
    
         
            +
             
     | 
| 
      
 891 
     | 
    
         
            +
            Visit `http://localhost:3000`
         
     | 
| 
      
 892 
     | 
    
         
            +
             
     | 
| 
      
 893 
     | 
    
         
            +
            You should see "Tic Tac Toe"
         
     | 
| 
      
 894 
     | 
    
         
            +
             
     | 
| 
      
 895 
     | 
    
         
            +
            
         
     | 
| 
      
 896 
     | 
    
         
            +
            
         
     | 
| 
      
 897 
     | 
    
         
            +
            
         
     | 
| 
      
 898 
     | 
    
         
            +
             
     | 
| 
      
 899 
     | 
    
         
            +
            #### Contact Manager
         
     | 
| 
      
 900 
     | 
    
         
            +
             
     | 
| 
      
 901 
     | 
    
         
            +
            Add the following require statement to `app/assets/javascripts/application.rb`
         
     | 
| 
      
 902 
     | 
    
         
            +
             
     | 
| 
      
 903 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 904 
     | 
    
         
            +
            require 'samples/elaborate/contact_manager'
         
     | 
| 
      
 905 
     | 
    
         
            +
            ```
         
     | 
| 
      
 906 
     | 
    
         
            +
             
     | 
| 
      
 907 
     | 
    
         
            +
            Or add the Glimmer code directly if you prefer to play around with it:
         
     | 
| 
      
 908 
     | 
    
         
            +
             
     | 
| 
      
 909 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 910 
     | 
    
         
            +
            class ContactManager
         
     | 
| 
      
 911 
     | 
    
         
            +
              class Contact
         
     | 
| 
      
 912 
     | 
    
         
            +
                attr_accessor :first_name, :last_name, :email
         
     | 
| 
      
 913 
     | 
    
         
            +
              
         
     | 
| 
      
 914 
     | 
    
         
            +
                def initialize(attribute_map)
         
     | 
| 
      
 915 
     | 
    
         
            +
                  @first_name = attribute_map[:first_name]
         
     | 
| 
      
 916 
     | 
    
         
            +
                  @last_name = attribute_map[:last_name]
         
     | 
| 
      
 917 
     | 
    
         
            +
                  @email = attribute_map[:email]
         
     | 
| 
      
 918 
     | 
    
         
            +
                end
         
     | 
| 
      
 919 
     | 
    
         
            +
              end
         
     | 
| 
      
 920 
     | 
    
         
            +
            end
         
     | 
| 
      
 921 
     | 
    
         
            +
             
     | 
| 
      
 922 
     | 
    
         
            +
            class ContactManager
         
     | 
| 
      
 923 
     | 
    
         
            +
              class ContactRepository
         
     | 
| 
      
 924 
     | 
    
         
            +
                NAMES_FIRST = %w[
         
     | 
| 
      
 925 
     | 
    
         
            +
                  Liam
         
     | 
| 
      
 926 
     | 
    
         
            +
                  Noah
         
     | 
| 
      
 927 
     | 
    
         
            +
                  William
         
     | 
| 
      
 928 
     | 
    
         
            +
                  James
         
     | 
| 
      
 929 
     | 
    
         
            +
                  Oliver
         
     | 
| 
      
 930 
     | 
    
         
            +
                  Benjamin
         
     | 
| 
      
 931 
     | 
    
         
            +
                  Elijah
         
     | 
| 
      
 932 
     | 
    
         
            +
                  Lucas
         
     | 
| 
      
 933 
     | 
    
         
            +
                  Mason
         
     | 
| 
      
 934 
     | 
    
         
            +
                  Logan
         
     | 
| 
      
 935 
     | 
    
         
            +
                  Alexander
         
     | 
| 
      
 936 
     | 
    
         
            +
                  Ethan
         
     | 
| 
      
 937 
     | 
    
         
            +
                  Jacob
         
     | 
| 
      
 938 
     | 
    
         
            +
                  Michael
         
     | 
| 
      
 939 
     | 
    
         
            +
                  Daniel
         
     | 
| 
      
 940 
     | 
    
         
            +
                  Henry
         
     | 
| 
      
 941 
     | 
    
         
            +
                  Jackson
         
     | 
| 
      
 942 
     | 
    
         
            +
                  Sebastian
         
     | 
| 
      
 943 
     | 
    
         
            +
                  Aiden
         
     | 
| 
      
 944 
     | 
    
         
            +
                  Matthew
         
     | 
| 
      
 945 
     | 
    
         
            +
                  Samuel
         
     | 
| 
      
 946 
     | 
    
         
            +
                  David
         
     | 
| 
      
 947 
     | 
    
         
            +
                  Joseph
         
     | 
| 
      
 948 
     | 
    
         
            +
                  Carter
         
     | 
| 
      
 949 
     | 
    
         
            +
                  Owen
         
     | 
| 
      
 950 
     | 
    
         
            +
                  Wyatt
         
     | 
| 
      
 951 
     | 
    
         
            +
                  John
         
     | 
| 
      
 952 
     | 
    
         
            +
                  Jack
         
     | 
| 
      
 953 
     | 
    
         
            +
                  Luke
         
     | 
| 
      
 954 
     | 
    
         
            +
                  Jayden
         
     | 
| 
      
 955 
     | 
    
         
            +
                  Dylan
         
     | 
| 
      
 956 
     | 
    
         
            +
                  Grayson
         
     | 
| 
      
 957 
     | 
    
         
            +
                  Levi
         
     | 
| 
      
 958 
     | 
    
         
            +
                  Isaac
         
     | 
| 
      
 959 
     | 
    
         
            +
                  Gabriel
         
     | 
| 
      
 960 
     | 
    
         
            +
                  Julian
         
     | 
| 
      
 961 
     | 
    
         
            +
                  Mateo
         
     | 
| 
      
 962 
     | 
    
         
            +
                  Anthony
         
     | 
| 
      
 963 
     | 
    
         
            +
                  Jaxon
         
     | 
| 
      
 964 
     | 
    
         
            +
                  Lincoln
         
     | 
| 
      
 965 
     | 
    
         
            +
                  Joshua
         
     | 
| 
      
 966 
     | 
    
         
            +
                  Christopher
         
     | 
| 
      
 967 
     | 
    
         
            +
                  Andrew
         
     | 
| 
      
 968 
     | 
    
         
            +
                  Theodore
         
     | 
| 
      
 969 
     | 
    
         
            +
                  Caleb
         
     | 
| 
      
 970 
     | 
    
         
            +
                  Ryan
         
     | 
| 
      
 971 
     | 
    
         
            +
                  Asher
         
     | 
| 
      
 972 
     | 
    
         
            +
                  Nathan
         
     | 
| 
      
 973 
     | 
    
         
            +
                  Thomas
         
     | 
| 
      
 974 
     | 
    
         
            +
                  Leo
         
     | 
| 
      
 975 
     | 
    
         
            +
                  Isaiah
         
     | 
| 
      
 976 
     | 
    
         
            +
                  Charles
         
     | 
| 
      
 977 
     | 
    
         
            +
                  Josiah
         
     | 
| 
      
 978 
     | 
    
         
            +
                  Hudson
         
     | 
| 
      
 979 
     | 
    
         
            +
                  Christian
         
     | 
| 
      
 980 
     | 
    
         
            +
                  Hunter
         
     | 
| 
      
 981 
     | 
    
         
            +
                  Connor
         
     | 
| 
      
 982 
     | 
    
         
            +
                  Eli
         
     | 
| 
      
 983 
     | 
    
         
            +
                  Ezra
         
     | 
| 
      
 984 
     | 
    
         
            +
                  Aaron
         
     | 
| 
      
 985 
     | 
    
         
            +
                  Landon
         
     | 
| 
      
 986 
     | 
    
         
            +
                  Adrian
         
     | 
| 
      
 987 
     | 
    
         
            +
                  Jonathan
         
     | 
| 
      
 988 
     | 
    
         
            +
                  Nolan
         
     | 
| 
      
 989 
     | 
    
         
            +
                  Jeremiah
         
     | 
| 
      
 990 
     | 
    
         
            +
                  Easton
         
     | 
| 
      
 991 
     | 
    
         
            +
                  Elias
         
     | 
| 
      
 992 
     | 
    
         
            +
                  Colton
         
     | 
| 
      
 993 
     | 
    
         
            +
                  Cameron
         
     | 
| 
      
 994 
     | 
    
         
            +
                  Carson
         
     | 
| 
      
 995 
     | 
    
         
            +
                  Robert
         
     | 
| 
      
 996 
     | 
    
         
            +
                  Angel
         
     | 
| 
      
 997 
     | 
    
         
            +
                  Maverick
         
     | 
| 
      
 998 
     | 
    
         
            +
                  Nicholas
         
     | 
| 
      
 999 
     | 
    
         
            +
                  Dominic
         
     | 
| 
      
 1000 
     | 
    
         
            +
                  Jaxson
         
     | 
| 
      
 1001 
     | 
    
         
            +
                  Greyson
         
     | 
| 
      
 1002 
     | 
    
         
            +
                  Adam
         
     | 
| 
      
 1003 
     | 
    
         
            +
                  Ian
         
     | 
| 
      
 1004 
     | 
    
         
            +
                  Austin
         
     | 
| 
      
 1005 
     | 
    
         
            +
                  Santiago
         
     | 
| 
      
 1006 
     | 
    
         
            +
                  Jordan
         
     | 
| 
      
 1007 
     | 
    
         
            +
                  Cooper
         
     | 
| 
      
 1008 
     | 
    
         
            +
                  Brayden
         
     | 
| 
      
 1009 
     | 
    
         
            +
                  Roman
         
     | 
| 
      
 1010 
     | 
    
         
            +
                  Evan
         
     | 
| 
      
 1011 
     | 
    
         
            +
                  Ezekiel
         
     | 
| 
      
 1012 
     | 
    
         
            +
                  Xaviar
         
     | 
| 
      
 1013 
     | 
    
         
            +
                  Jose
         
     | 
| 
      
 1014 
     | 
    
         
            +
                  Jace
         
     | 
| 
      
 1015 
     | 
    
         
            +
                  Jameson
         
     | 
| 
      
 1016 
     | 
    
         
            +
                  Leonardo
         
     | 
| 
      
 1017 
     | 
    
         
            +
                  Axel
         
     | 
| 
      
 1018 
     | 
    
         
            +
                  Everett
         
     | 
| 
      
 1019 
     | 
    
         
            +
                  Kayden
         
     | 
| 
      
 1020 
     | 
    
         
            +
                  Miles
         
     | 
| 
      
 1021 
     | 
    
         
            +
                  Sawyer
         
     | 
| 
      
 1022 
     | 
    
         
            +
                  Jason
         
     | 
| 
      
 1023 
     | 
    
         
            +
                  Emma
         
     | 
| 
      
 1024 
     | 
    
         
            +
                  Olivia
         
     | 
| 
      
 1025 
     | 
    
         
            +
                  Ava
         
     | 
| 
      
 1026 
     | 
    
         
            +
                  Isabella
         
     | 
| 
      
 1027 
     | 
    
         
            +
                  Sophia
         
     | 
| 
      
 1028 
     | 
    
         
            +
                  Charlotte
         
     | 
| 
      
 1029 
     | 
    
         
            +
                  Mia
         
     | 
| 
      
 1030 
     | 
    
         
            +
                  Amelia
         
     | 
| 
      
 1031 
     | 
    
         
            +
                  Harper
         
     | 
| 
      
 1032 
     | 
    
         
            +
                  Evelyn
         
     | 
| 
      
 1033 
     | 
    
         
            +
                  Abigail
         
     | 
| 
      
 1034 
     | 
    
         
            +
                  Emily
         
     | 
| 
      
 1035 
     | 
    
         
            +
                  Elizabeth
         
     | 
| 
      
 1036 
     | 
    
         
            +
                  Mila
         
     | 
| 
      
 1037 
     | 
    
         
            +
                  Ella
         
     | 
| 
      
 1038 
     | 
    
         
            +
                  Avery
         
     | 
| 
      
 1039 
     | 
    
         
            +
                  Sofia
         
     | 
| 
      
 1040 
     | 
    
         
            +
                  Camila
         
     | 
| 
      
 1041 
     | 
    
         
            +
                  Aria
         
     | 
| 
      
 1042 
     | 
    
         
            +
                  Scarlett
         
     | 
| 
      
 1043 
     | 
    
         
            +
                  Victoria
         
     | 
| 
      
 1044 
     | 
    
         
            +
                  Madison
         
     | 
| 
      
 1045 
     | 
    
         
            +
                  Luna
         
     | 
| 
      
 1046 
     | 
    
         
            +
                  Grace
         
     | 
| 
      
 1047 
     | 
    
         
            +
                  Chloe
         
     | 
| 
      
 1048 
     | 
    
         
            +
                  Penelope
         
     | 
| 
      
 1049 
     | 
    
         
            +
                  Layla
         
     | 
| 
      
 1050 
     | 
    
         
            +
                  Riley
         
     | 
| 
      
 1051 
     | 
    
         
            +
                  Zoey
         
     | 
| 
      
 1052 
     | 
    
         
            +
                  Nora
         
     | 
| 
      
 1053 
     | 
    
         
            +
                  Lily
         
     | 
| 
      
 1054 
     | 
    
         
            +
                  Eleanor
         
     | 
| 
      
 1055 
     | 
    
         
            +
                  Hannah
         
     | 
| 
      
 1056 
     | 
    
         
            +
                  Lillian
         
     | 
| 
      
 1057 
     | 
    
         
            +
                  Addison
         
     | 
| 
      
 1058 
     | 
    
         
            +
                  Aubrey
         
     | 
| 
      
 1059 
     | 
    
         
            +
                  Ellie
         
     | 
| 
      
 1060 
     | 
    
         
            +
                  Stella
         
     | 
| 
      
 1061 
     | 
    
         
            +
                  Natalie
         
     | 
| 
      
 1062 
     | 
    
         
            +
                  Zoe
         
     | 
| 
      
 1063 
     | 
    
         
            +
                  Leah
         
     | 
| 
      
 1064 
     | 
    
         
            +
                  Hazel
         
     | 
| 
      
 1065 
     | 
    
         
            +
                  Violet
         
     | 
| 
      
 1066 
     | 
    
         
            +
                  Aurora
         
     | 
| 
      
 1067 
     | 
    
         
            +
                  Savannah
         
     | 
| 
      
 1068 
     | 
    
         
            +
                  Audrey
         
     | 
| 
      
 1069 
     | 
    
         
            +
                  Brooklyn
         
     | 
| 
      
 1070 
     | 
    
         
            +
                  Bella
         
     | 
| 
      
 1071 
     | 
    
         
            +
                  Claire
         
     | 
| 
      
 1072 
     | 
    
         
            +
                  Skylar
         
     | 
| 
      
 1073 
     | 
    
         
            +
                  Lucy
         
     | 
| 
      
 1074 
     | 
    
         
            +
                  Paisley
         
     | 
| 
      
 1075 
     | 
    
         
            +
                  Everly
         
     | 
| 
      
 1076 
     | 
    
         
            +
                  Anna
         
     | 
| 
      
 1077 
     | 
    
         
            +
                  Caroline
         
     | 
| 
      
 1078 
     | 
    
         
            +
                  Nova
         
     | 
| 
      
 1079 
     | 
    
         
            +
                  Genesis
         
     | 
| 
      
 1080 
     | 
    
         
            +
                  Emilia
         
     | 
| 
      
 1081 
     | 
    
         
            +
                  Kennedy
         
     | 
| 
      
 1082 
     | 
    
         
            +
                  Samantha
         
     | 
| 
      
 1083 
     | 
    
         
            +
                  Maya
         
     | 
| 
      
 1084 
     | 
    
         
            +
                  Willow
         
     | 
| 
      
 1085 
     | 
    
         
            +
                  Kinsley
         
     | 
| 
      
 1086 
     | 
    
         
            +
                  Naomi
         
     | 
| 
      
 1087 
     | 
    
         
            +
                  Aaliyah
         
     | 
| 
      
 1088 
     | 
    
         
            +
                  Elena
         
     | 
| 
      
 1089 
     | 
    
         
            +
                  Sarah
         
     | 
| 
      
 1090 
     | 
    
         
            +
                  Ariana
         
     | 
| 
      
 1091 
     | 
    
         
            +
                  Allison
         
     | 
| 
      
 1092 
     | 
    
         
            +
                  Gabriella
         
     | 
| 
      
 1093 
     | 
    
         
            +
                  Alice
         
     | 
| 
      
 1094 
     | 
    
         
            +
                  Madelyn
         
     | 
| 
      
 1095 
     | 
    
         
            +
                  Cora
         
     | 
| 
      
 1096 
     | 
    
         
            +
                  Ruby
         
     | 
| 
      
 1097 
     | 
    
         
            +
                  Eva
         
     | 
| 
      
 1098 
     | 
    
         
            +
                  Serenity
         
     | 
| 
      
 1099 
     | 
    
         
            +
                  Autumn
         
     | 
| 
      
 1100 
     | 
    
         
            +
                  Adeline
         
     | 
| 
      
 1101 
     | 
    
         
            +
                  Hailey
         
     | 
| 
      
 1102 
     | 
    
         
            +
                  Gianna
         
     | 
| 
      
 1103 
     | 
    
         
            +
                  Valentina
         
     | 
| 
      
 1104 
     | 
    
         
            +
                  Isla
         
     | 
| 
      
 1105 
     | 
    
         
            +
                  Eliana
         
     | 
| 
      
 1106 
     | 
    
         
            +
                  Quinn
         
     | 
| 
      
 1107 
     | 
    
         
            +
                  Nevaeh
         
     | 
| 
      
 1108 
     | 
    
         
            +
                  Ivy
         
     | 
| 
      
 1109 
     | 
    
         
            +
                  Sadie
         
     | 
| 
      
 1110 
     | 
    
         
            +
                  Piper
         
     | 
| 
      
 1111 
     | 
    
         
            +
                  Lydia
         
     | 
| 
      
 1112 
     | 
    
         
            +
                  Alexa
         
     | 
| 
      
 1113 
     | 
    
         
            +
                  Josephine
         
     | 
| 
      
 1114 
     | 
    
         
            +
                  Emery
         
     | 
| 
      
 1115 
     | 
    
         
            +
                  Julia
         
     | 
| 
      
 1116 
     | 
    
         
            +
                  Delilah
         
     | 
| 
      
 1117 
     | 
    
         
            +
                  Arianna
         
     | 
| 
      
 1118 
     | 
    
         
            +
                  Vivian
         
     | 
| 
      
 1119 
     | 
    
         
            +
                  Kaylee
         
     | 
| 
      
 1120 
     | 
    
         
            +
                  Sophie
         
     | 
| 
      
 1121 
     | 
    
         
            +
                  Brielle
         
     | 
| 
      
 1122 
     | 
    
         
            +
                  Madeline
         
     | 
| 
      
 1123 
     | 
    
         
            +
                ]
         
     | 
| 
      
 1124 
     | 
    
         
            +
                NAMES_LAST = %w[
         
     | 
| 
      
 1125 
     | 
    
         
            +
                  Smith
         
     | 
| 
      
 1126 
     | 
    
         
            +
                  Johnson
         
     | 
| 
      
 1127 
     | 
    
         
            +
                  Williams
         
     | 
| 
      
 1128 
     | 
    
         
            +
                  Brown
         
     | 
| 
      
 1129 
     | 
    
         
            +
                  Jones
         
     | 
| 
      
 1130 
     | 
    
         
            +
                  Miller
         
     | 
| 
      
 1131 
     | 
    
         
            +
                  Davis
         
     | 
| 
      
 1132 
     | 
    
         
            +
                  Wilson
         
     | 
| 
      
 1133 
     | 
    
         
            +
                  Anderson
         
     | 
| 
      
 1134 
     | 
    
         
            +
                  Taylor
         
     | 
| 
      
 1135 
     | 
    
         
            +
                ]
         
     | 
| 
      
 1136 
     | 
    
         
            +
                def initialize(contacts = nil)
         
     | 
| 
      
 1137 
     | 
    
         
            +
                  @contacts = contacts || 1000.times.map do |n|
         
     | 
| 
      
 1138 
     | 
    
         
            +
                    random_first_name_index = (rand*NAMES_FIRST.size).to_i
         
     | 
| 
      
 1139 
     | 
    
         
            +
                    random_last_name_index = (rand*NAMES_LAST.size).to_i
         
     | 
| 
      
 1140 
     | 
    
         
            +
                    first_name = NAMES_FIRST[random_first_name_index]
         
     | 
| 
      
 1141 
     | 
    
         
            +
                    last_name = NAMES_LAST[random_last_name_index]
         
     | 
| 
      
 1142 
     | 
    
         
            +
                    email = "#{first_name}@#{last_name}.com".downcase
         
     | 
| 
      
 1143 
     | 
    
         
            +
                    Contact.new(
         
     | 
| 
      
 1144 
     | 
    
         
            +
                      first_name: first_name,
         
     | 
| 
      
 1145 
     | 
    
         
            +
                      last_name: last_name,
         
     | 
| 
      
 1146 
     | 
    
         
            +
                      email: email
         
     | 
| 
      
 1147 
     | 
    
         
            +
                    )
         
     | 
| 
      
 1148 
     | 
    
         
            +
                  end
         
     | 
| 
      
 1149 
     | 
    
         
            +
                end
         
     | 
| 
      
 1150 
     | 
    
         
            +
              
         
     | 
| 
      
 1151 
     | 
    
         
            +
                def find(attribute_filter_map)
         
     | 
| 
      
 1152 
     | 
    
         
            +
                  @contacts.find_all do |contact|
         
     | 
| 
      
 1153 
     | 
    
         
            +
                    match = true
         
     | 
| 
      
 1154 
     | 
    
         
            +
                    attribute_filter_map.keys.each do |attribute_name|
         
     | 
| 
      
 1155 
     | 
    
         
            +
                      contact_value = contact.send(attribute_name).downcase
         
     | 
| 
      
 1156 
     | 
    
         
            +
                      filter_value = attribute_filter_map[attribute_name].downcase
         
     | 
| 
      
 1157 
     | 
    
         
            +
                      match = false unless contact_value.match(filter_value)
         
     | 
| 
      
 1158 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1159 
     | 
    
         
            +
                    match
         
     | 
| 
      
 1160 
     | 
    
         
            +
                  end
         
     | 
| 
      
 1161 
     | 
    
         
            +
                end
         
     | 
| 
      
 1162 
     | 
    
         
            +
              end
         
     | 
| 
      
 1163 
     | 
    
         
            +
            end
         
     | 
| 
      
 1164 
     | 
    
         
            +
             
     | 
| 
      
 1165 
     | 
    
         
            +
            class ContactManager
         
     | 
| 
      
 1166 
     | 
    
         
            +
              class ContactManagerPresenter
         
     | 
| 
      
 1167 
     | 
    
         
            +
                attr_accessor :results
         
     | 
| 
      
 1168 
     | 
    
         
            +
                @@contact_attributes = [:first_name, :last_name, :email]
         
     | 
| 
      
 1169 
     | 
    
         
            +
                @@contact_attributes.each {|attribute_name| attr_accessor attribute_name}
         
     | 
| 
      
 1170 
     | 
    
         
            +
              
         
     | 
| 
      
 1171 
     | 
    
         
            +
                def initialize(contact_repository = nil)
         
     | 
| 
      
 1172 
     | 
    
         
            +
                  @contact_repository = contact_repository || ContactRepository.new
         
     | 
| 
      
 1173 
     | 
    
         
            +
                  @results = []
         
     | 
| 
      
 1174 
     | 
    
         
            +
                end
         
     | 
| 
      
 1175 
     | 
    
         
            +
              
         
     | 
| 
      
 1176 
     | 
    
         
            +
                def list
         
     | 
| 
      
 1177 
     | 
    
         
            +
                  self.results = @contact_repository.find({})
         
     | 
| 
      
 1178 
     | 
    
         
            +
                end
         
     | 
| 
      
 1179 
     | 
    
         
            +
              
         
     | 
| 
      
 1180 
     | 
    
         
            +
                def find
         
     | 
| 
      
 1181 
     | 
    
         
            +
                  filter_map = {}
         
     | 
| 
      
 1182 
     | 
    
         
            +
                  @@contact_attributes.each do |attribute_name|
         
     | 
| 
      
 1183 
     | 
    
         
            +
                    filter_map[attribute_name] = self.send(attribute_name) if self.send(attribute_name)
         
     | 
| 
      
 1184 
     | 
    
         
            +
                  end
         
     | 
| 
      
 1185 
     | 
    
         
            +
                  self.results = @contact_repository.find(filter_map)
         
     | 
| 
      
 1186 
     | 
    
         
            +
                  @sort_attribute_name = nil
         
     | 
| 
      
 1187 
     | 
    
         
            +
                  @sort_direction_ascending = nil
         
     | 
| 
      
 1188 
     | 
    
         
            +
                end
         
     | 
| 
      
 1189 
     | 
    
         
            +
              
         
     | 
| 
      
 1190 
     | 
    
         
            +
                def toggle_sort(attribute_name)
         
     | 
| 
      
 1191 
     | 
    
         
            +
                  @sort_attribute_name = attribute_name
         
     | 
| 
      
 1192 
     | 
    
         
            +
                  @sort_direction_ascending = !@sort_direction_ascending
         
     | 
| 
      
 1193 
     | 
    
         
            +
                  sorted_results = self.results.sort_by {|contact| contact.send(attribute_name).downcase}
         
     | 
| 
      
 1194 
     | 
    
         
            +
                  sorted_results = sorted_results.reverse unless @sort_direction_ascending
         
     | 
| 
      
 1195 
     | 
    
         
            +
                  self.results = sorted_results
         
     | 
| 
      
 1196 
     | 
    
         
            +
                end
         
     | 
| 
      
 1197 
     | 
    
         
            +
              end
         
     | 
| 
      
 1198 
     | 
    
         
            +
            end
         
     | 
| 
      
 1199 
     | 
    
         
            +
             
     | 
| 
      
 1200 
     | 
    
         
            +
            class ContactManager
         
     | 
| 
      
 1201 
     | 
    
         
            +
              include Glimmer
         
     | 
| 
      
 1202 
     | 
    
         
            +
             
     | 
| 
      
 1203 
     | 
    
         
            +
              def initialize
         
     | 
| 
      
 1204 
     | 
    
         
            +
                @contact_manager_presenter = ContactManagerPresenter.new
         
     | 
| 
      
 1205 
     | 
    
         
            +
                @contact_manager_presenter.list
         
     | 
| 
      
 1206 
     | 
    
         
            +
              end
         
     | 
| 
      
 1207 
     | 
    
         
            +
             
     | 
| 
      
 1208 
     | 
    
         
            +
              def launch
         
     | 
| 
      
 1209 
     | 
    
         
            +
                shell {
         
     | 
| 
      
 1210 
     | 
    
         
            +
                  text "Contact Manager"
         
     | 
| 
      
 1211 
     | 
    
         
            +
                  composite {
         
     | 
| 
      
 1212 
     | 
    
         
            +
                    composite {
         
     | 
| 
      
 1213 
     | 
    
         
            +
                      grid_layout 2, false
         
     | 
| 
      
 1214 
     | 
    
         
            +
                      label {text "First &Name: "}
         
     | 
| 
      
 1215 
     | 
    
         
            +
                      text {
         
     | 
| 
      
 1216 
     | 
    
         
            +
                        text bind(@contact_manager_presenter, :first_name)
         
     | 
| 
      
 1217 
     | 
    
         
            +
                        on_key_pressed {|key_event|
         
     | 
| 
      
 1218 
     | 
    
         
            +
                          @contact_manager_presenter.find if key_event.keyCode == Glimmer::SWT::SWTProxy[:cr]
         
     | 
| 
      
 1219 
     | 
    
         
            +
                        }
         
     | 
| 
      
 1220 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1221 
     | 
    
         
            +
                      label {text "&Last Name: "}
         
     | 
| 
      
 1222 
     | 
    
         
            +
                      text {
         
     | 
| 
      
 1223 
     | 
    
         
            +
                        text bind(@contact_manager_presenter, :last_name)
         
     | 
| 
      
 1224 
     | 
    
         
            +
                        on_key_pressed {|key_event|
         
     | 
| 
      
 1225 
     | 
    
         
            +
                          @contact_manager_presenter.find if key_event.keyCode == Glimmer::SWT::SWTProxy[:cr]
         
     | 
| 
      
 1226 
     | 
    
         
            +
                        }
         
     | 
| 
      
 1227 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1228 
     | 
    
         
            +
                      label {text "&Email: "}
         
     | 
| 
      
 1229 
     | 
    
         
            +
                      text {
         
     | 
| 
      
 1230 
     | 
    
         
            +
                        text bind(@contact_manager_presenter, :email)
         
     | 
| 
      
 1231 
     | 
    
         
            +
                        on_key_pressed {|key_event|
         
     | 
| 
      
 1232 
     | 
    
         
            +
                          @contact_manager_presenter.find if key_event.keyCode == Glimmer::SWT::SWTProxy[:cr]
         
     | 
| 
      
 1233 
     | 
    
         
            +
                        }
         
     | 
| 
      
 1234 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1235 
     | 
    
         
            +
                      composite {
         
     | 
| 
      
 1236 
     | 
    
         
            +
                        grid_layout 2, false
         
     | 
| 
      
 1237 
     | 
    
         
            +
                        button {
         
     | 
| 
      
 1238 
     | 
    
         
            +
                          text "&Find"
         
     | 
| 
      
 1239 
     | 
    
         
            +
                          on_widget_selected {
         
     | 
| 
      
 1240 
     | 
    
         
            +
                            @contact_manager_presenter.find
         
     | 
| 
      
 1241 
     | 
    
         
            +
                          }
         
     | 
| 
      
 1242 
     | 
    
         
            +
                        }
         
     | 
| 
      
 1243 
     | 
    
         
            +
                        button {
         
     | 
| 
      
 1244 
     | 
    
         
            +
                          text "&List All"
         
     | 
| 
      
 1245 
     | 
    
         
            +
                          on_widget_selected {
         
     | 
| 
      
 1246 
     | 
    
         
            +
                            @contact_manager_presenter.list
         
     | 
| 
      
 1247 
     | 
    
         
            +
                          }
         
     | 
| 
      
 1248 
     | 
    
         
            +
                        }
         
     | 
| 
      
 1249 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1250 
     | 
    
         
            +
                    }
         
     | 
| 
      
 1251 
     | 
    
         
            +
             
     | 
| 
      
 1252 
     | 
    
         
            +
                    table(:multi) { |table_proxy|
         
     | 
| 
      
 1253 
     | 
    
         
            +
                      layout_data {
         
     | 
| 
      
 1254 
     | 
    
         
            +
                        horizontal_alignment :fill
         
     | 
| 
      
 1255 
     | 
    
         
            +
                        vertical_alignment :fill
         
     | 
| 
      
 1256 
     | 
    
         
            +
                        grab_excess_horizontal_space true
         
     | 
| 
      
 1257 
     | 
    
         
            +
                        grab_excess_vertical_space true
         
     | 
| 
      
 1258 
     | 
    
         
            +
                        height_hint 200
         
     | 
| 
      
 1259 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1260 
     | 
    
         
            +
                      table_column {
         
     | 
| 
      
 1261 
     | 
    
         
            +
                        text "First Name"
         
     | 
| 
      
 1262 
     | 
    
         
            +
                        width 80
         
     | 
| 
      
 1263 
     | 
    
         
            +
                        on_widget_selected {
         
     | 
| 
      
 1264 
     | 
    
         
            +
                          @contact_manager_presenter.toggle_sort(:first_name)
         
     | 
| 
      
 1265 
     | 
    
         
            +
                        }
         
     | 
| 
      
 1266 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1267 
     | 
    
         
            +
                      table_column {
         
     | 
| 
      
 1268 
     | 
    
         
            +
                        text "Last Name"
         
     | 
| 
      
 1269 
     | 
    
         
            +
                        width 80
         
     | 
| 
      
 1270 
     | 
    
         
            +
                        on_widget_selected {
         
     | 
| 
      
 1271 
     | 
    
         
            +
                          @contact_manager_presenter.toggle_sort(:last_name)
         
     | 
| 
      
 1272 
     | 
    
         
            +
                        }
         
     | 
| 
      
 1273 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1274 
     | 
    
         
            +
                      table_column {
         
     | 
| 
      
 1275 
     | 
    
         
            +
                        text "Email"
         
     | 
| 
      
 1276 
     | 
    
         
            +
                        width 200
         
     | 
| 
      
 1277 
     | 
    
         
            +
                        on_widget_selected {
         
     | 
| 
      
 1278 
     | 
    
         
            +
                          @contact_manager_presenter.toggle_sort(:email)
         
     | 
| 
      
 1279 
     | 
    
         
            +
                        }
         
     | 
| 
      
 1280 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1281 
     | 
    
         
            +
                      items bind(@contact_manager_presenter, :results), column_properties(:first_name, :last_name, :email)
         
     | 
| 
      
 1282 
     | 
    
         
            +
                      on_mouse_down { |event|
         
     | 
| 
      
 1283 
     | 
    
         
            +
                        table_proxy.edit_table_item(event.table_item, event.column_index)
         
     | 
| 
      
 1284 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1285 
     | 
    
         
            +
                    }
         
     | 
| 
      
 1286 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1287 
     | 
    
         
            +
                }.open
         
     | 
| 
      
 1288 
     | 
    
         
            +
              end
         
     | 
| 
      
 1289 
     | 
    
         
            +
            end
         
     | 
| 
      
 1290 
     | 
    
         
            +
             
     | 
| 
      
 1291 
     | 
    
         
            +
            ContactManager.new.launch
         
     | 
| 
      
 1292 
     | 
    
         
            +
             
     | 
| 
      
 1293 
     | 
    
         
            +
            ```
         
     | 
| 
      
 1294 
     | 
    
         
            +
            Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
         
     | 
| 
      
 1295 
     | 
    
         
            +
             
     | 
| 
      
 1296 
     | 
    
         
            +
            Glimmer DSL for SWT Contact Manager
         
     | 
| 
      
 1297 
     | 
    
         
            +
             
     | 
| 
      
 1298 
     | 
    
         
            +
            
         
     | 
| 
      
 1299 
     | 
    
         
            +
             
     | 
| 
      
 1300 
     | 
    
         
            +
            Glimmer DSL for SWT Contact Manager Find
         
     | 
| 
      
 1301 
     | 
    
         
            +
             
     | 
| 
      
 1302 
     | 
    
         
            +
            
         
     | 
| 
      
 1303 
     | 
    
         
            +
             
     | 
| 
      
 1304 
     | 
    
         
            +
            Glimmer DSL for SWT Contact Manager Edit Started
         
     | 
| 
      
 1305 
     | 
    
         
            +
             
     | 
| 
      
 1306 
     | 
    
         
            +
            
         
     | 
| 
      
 1307 
     | 
    
         
            +
             
     | 
| 
      
 1308 
     | 
    
         
            +
            Glimmer DSL for SWT Contact Manager Edit In Progress
         
     | 
| 
      
 1309 
     | 
    
         
            +
             
     | 
| 
      
 1310 
     | 
    
         
            +
            
         
     | 
| 
      
 1311 
     | 
    
         
            +
             
     | 
| 
      
 1312 
     | 
    
         
            +
            Glimmer DSL for SWT Contact Manager Edit Done
         
     | 
| 
      
 1313 
     | 
    
         
            +
             
     | 
| 
      
 1314 
     | 
    
         
            +
            
         
     | 
| 
      
 1315 
     | 
    
         
            +
             
     | 
| 
      
 1316 
     | 
    
         
            +
            Glimmer app on the web (using `glimmer-dsl-opal` gem):
         
     | 
| 
      
 1317 
     | 
    
         
            +
             
     | 
| 
      
 1318 
     | 
    
         
            +
            Start the Rails server:
         
     | 
| 
      
 1319 
     | 
    
         
            +
            ```
         
     | 
| 
      
 1320 
     | 
    
         
            +
            rails s
         
     | 
| 
      
 1321 
     | 
    
         
            +
            ```
         
     | 
| 
      
 1322 
     | 
    
         
            +
             
     | 
| 
      
 1323 
     | 
    
         
            +
            Visit `http://localhost:3000`
         
     | 
| 
      
 1324 
     | 
    
         
            +
             
     | 
| 
      
 1325 
     | 
    
         
            +
            You should see "Tic Tac Toe"
         
     | 
| 
      
 1326 
     | 
    
         
            +
             
     | 
| 
      
 1327 
     | 
    
         
            +
            Glimmer DSL for Opal Contact Manager
         
     | 
| 
      
 1328 
     | 
    
         
            +
             
     | 
| 
      
 1329 
     | 
    
         
            +
            
         
     | 
| 
      
 1330 
     | 
    
         
            +
             
     | 
| 
      
 1331 
     | 
    
         
            +
            Glimmer DSL for Opal Contact Manager Find
         
     | 
| 
      
 1332 
     | 
    
         
            +
             
     | 
| 
      
 1333 
     | 
    
         
            +
            
         
     | 
| 
      
 1334 
     | 
    
         
            +
             
     | 
| 
      
 1335 
     | 
    
         
            +
            Glimmer DSL for Opal Contact Manager Edit Started
         
     | 
| 
      
 1336 
     | 
    
         
            +
             
     | 
| 
      
 1337 
     | 
    
         
            +
            
         
     | 
| 
      
 1338 
     | 
    
         
            +
             
     | 
| 
      
 1339 
     | 
    
         
            +
            Glimmer DSL for Opal Contact Manager Edit In Progress
         
     | 
| 
      
 1340 
     | 
    
         
            +
             
     | 
| 
      
 1341 
     | 
    
         
            +
            
         
     | 
| 
      
 1342 
     | 
    
         
            +
             
     | 
| 
      
 1343 
     | 
    
         
            +
            Glimmer DSL for Opal Contact Manager Edit Done
         
     | 
| 
      
 1344 
     | 
    
         
            +
             
     | 
| 
      
 1345 
     | 
    
         
            +
            
         
     | 
| 
      
 1346 
     | 
    
         
            +
             
     | 
| 
       398 
1347 
     | 
    
         
             
            ## Help
         
     | 
| 
       399 
1348 
     | 
    
         | 
| 
       400 
1349 
     | 
    
         
             
            ### Issues
         
     |