glimmer 0.10.1 → 0.10.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +275 -71
- data/VERSION +1 -1
- data/lib/glimmer.rb +1 -0
- data/lib/glimmer/config.rb +3 -9
- data/lib/glimmer/data_binding/observable_array.rb +224 -21
- data/lib/glimmer/data_binding/observable_model.rb +1 -1
- data/lib/glimmer/data_binding/observer.rb +1 -0
- metadata +22 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f5296edf57183b7bffa288342e5c3c4ab14713dbd70af643bf8117f608314d2a
|
4
|
+
data.tar.gz: 5a9285de28140f0f7a94ed80ec9c6c597ae163a5fdce4f4ad8a060f5ad341775
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ef36cf024e59cc0111d8f3a283c6d89134eea01390574962ef0b36ef89c75d482d6912b83fd1bfc609f40f262f72156df9ab8d8481ac41118bb799b1a718e473
|
7
|
+
data.tar.gz: 65c0d12d30f2ea846766d98bb91aa0b3ae86eaac11697532d6b3ed55a139816d0be797a94584297c40c949f8cff436dfa15cbc0176cbb652207bab452c148071
|
data/README.md
CHANGED
@@ -1,14 +1,17 @@
|
|
1
|
-
# <img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 style="position: relative; top: 20px;" /> Glimmer (Ruby Desktop Development GUI Library)
|
1
|
+
# [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 style="position: relative; top: 20px;" />](https://rubygems.org/gems/glimmer) Glimmer (Ruby Desktop Development GUI Library)
|
2
2
|
[![Gem Version](https://badge.fury.io/rb/glimmer.svg)](http://badge.fury.io/rb/glimmer)
|
3
3
|
[![Travis CI](https://travis-ci.com/AndyObtiva/glimmer.svg?branch=master)](https://travis-ci.com/github/AndyObtiva/glimmer)
|
4
4
|
[![Coverage Status](https://coveralls.io/repos/github/AndyObtiva/glimmer/badge.svg?branch=master)](https://coveralls.io/github/AndyObtiva/glimmer?branch=master)
|
5
|
+
[![Maintainability](https://api.codeclimate.com/v1/badges/38fbc278022862794414/maintainability)](https://codeclimate.com/github/AndyObtiva/glimmer/maintainability)
|
5
6
|
[![Join the chat at https://gitter.im/AndyObtiva/glimmer](https://badges.gitter.im/AndyObtiva/glimmer.svg)](https://gitter.im/AndyObtiva/glimmer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
6
7
|
|
7
8
|
**[Contributors Wanted! (Submit a Glimmer App Sample to Get Started)](#contributing)**
|
8
9
|
|
9
10
|
(The Original Glimmer Library Since 2007. Beware of Imitators!)
|
10
11
|
|
11
|
-
[**Glimmer**](https://rubygems.org/gems/glimmer) is a native-GUI cross-platform desktop development library written in [JRuby](https://www.jruby.org/),
|
12
|
+
[**Glimmer**](https://rubygems.org/gems/glimmer) is a native-GUI cross-platform desktop development library written in [JRuby](https://www.jruby.org/), an OS-threaded faster version of [Ruby](https://www.ruby-lang.org/en/). [Glimmer](https://rubygems.org/gems/glimmer)'s main innovation is a declarative [Ruby DSL](#glimmer-dsl-syntax) that enables productive and efficient authoring of desktop application user-interfaces while relying on the robust [Eclipse SWT library](https://www.eclipse.org/swt/). [Glimmer](https://rubygems.org/gems/glimmer) additionally innovates by having built-in [data-binding](#data-binding) support, which greatly facilitates synchronizing the GUI with domain models, thus achieving true decoupling of object oriented components and enabling developers to solve business problems (test-first) without worrying about GUI concerns. To get started quickly, [Glimmer](https://rubygems.org/gems/glimmer) offers [scaffolding](#scaffolding) options for [Apps](#in-production), [Gems](#custom-shell-gem), and [Custom Widgets](#custom-widgets). [Glimmer](https://rubygems.org/gems/glimmer) also includes native-executable [packaging](#packaging--distribution) support, sorely lacking in other libraries, thus enabling the delivery of desktop apps written in [Ruby](https://www.ruby-lang.org/en/) as truly native DMG/PKG/APP files on the [Mac](https://www.apple.com/ca/macos) + [App Store](https://developer.apple.com/macos/distribution/) and MSI/EXE files on [Windows](https://www.microsoft.com/en-ca/windows). Unlike libraries like TK, [Glimmer](https://rubygems.org/gems/glimmer) does not require recompilation of [Ruby](https://www.ruby-lang.org/en/). [Glimmer](https://rubygems.org/gems/glimmer) runs native GUI out of the box on every platform thanks to the [JVM](https://java.com/en/download/faq/whatis_java.xml), [JRuby](https://www.jruby.org/), and the [Eclipse SWT library](https://www.eclipse.org/swt/).
|
13
|
+
|
14
|
+
NOTE: Glimmer is in beta mode. Please help make better by [contributing](#contributing), adopting for small or low risk projects, and providing feedback. While a lot of hard work has gone into it, it is by no means polished, and definitely has bugs waiting to be reported. The more feedback and issues you report the better.
|
12
15
|
|
13
16
|
[<img src="https://covers.oreillystatic.com/images/9780596519650/lrg.jpg" width=105 /><br />
|
14
17
|
Featured in<br />JRuby Cookbook](http://shop.oreilly.com/product/9780596519650.do)
|
@@ -171,8 +174,6 @@ Glimmer App:
|
|
171
174
|
|
172
175
|
![Contact Manager](images/glimmer-contact-manager.png)
|
173
176
|
|
174
|
-
NOTE: Glimmer is in beta mode. Please help make better by [contributing](#contributing), adopting for small or low risk projects, and providing feedback.
|
175
|
-
|
176
177
|
## Table of contents
|
177
178
|
|
178
179
|
- [Glimmer (Ruby Desktop Development GUI Library)](#-glimmer-ruby-desktop-development-gui-library)
|
@@ -202,7 +203,7 @@ NOTE: Glimmer is in beta mode. Please help make better by [contributing](#contri
|
|
202
203
|
- [Raw JRuby Command](#raw-jruby-command)
|
203
204
|
- [Mac Support](#mac-support)
|
204
205
|
- [Girb (Glimmer irb) Command](#girb-glimmer-irb-command)
|
205
|
-
- [Glimmer DSL Syntax](#glimmer-dsl-syntax)
|
206
|
+
- [Glimmer GUI DSL Syntax](#glimmer-gui-dsl-syntax)
|
206
207
|
- [Widgets](#widgets)
|
207
208
|
- [Display](#display)
|
208
209
|
- [SWT Proxies](#swt-proxies)
|
@@ -272,6 +273,7 @@ NOTE: Glimmer is in beta mode. Please help make better by [contributing](#contri
|
|
272
273
|
- [In Production](#in-production)
|
273
274
|
- [Math Bowling](#math-bowling)
|
274
275
|
- [Are We There Yet?](#are-we-there-yet)
|
276
|
+
- [Garderie Rainbow Daily Agenda](#garderie-rainbow-daily-agenda)
|
275
277
|
- [Packaging & Distribution](#packaging--distribution)
|
276
278
|
- [Packaging Defaults](#packaging-defaults)
|
277
279
|
- [Packaging Configuration](#packaging-configuration)
|
@@ -279,6 +281,7 @@ NOTE: Glimmer is in beta mode. Please help make better by [contributing](#contri
|
|
279
281
|
- [Mac Application Distribution](#mac-application-distribution)
|
280
282
|
- [Self Signed Certificate](#self-signed-certificate)
|
281
283
|
- [Gotchas](#gotchas)
|
284
|
+
- [App Updates](#app-updates)
|
282
285
|
- [Resources](#resources)
|
283
286
|
- [Help](#help)
|
284
287
|
- [Issues](#issues)
|
@@ -313,18 +316,17 @@ https://www.eclipse.org/swt/faq.php
|
|
313
316
|
|
314
317
|
## Pre-requisites
|
315
318
|
|
316
|
-
- SWT 4.
|
317
|
-
- JRuby 9.2.
|
318
|
-
- JDK 8 (find at
|
319
|
-
- (Optional) RVM is needed for [Scaffolding](#scaffolding) only (find at [https://rvm.io/](https://rvm.io/))
|
319
|
+
- SWT 4.16 (comes included in Glimmer gem)
|
320
|
+
- JRuby 9.2.13.0 (supporting Ruby 2.5.x syntax) (get via [RVM](http://rvm.io) on Mac and Linux or find at [https://www.jruby.org/download](https://www.jruby.org/download) for Windows)
|
321
|
+
- JDK 8 (find at https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html)
|
320
322
|
|
321
|
-
|
323
|
+
To obtain JRuby through [RVM](http://rvm.io), you may run:
|
322
324
|
|
323
325
|
```bash
|
324
|
-
rvm install jruby-9.2.
|
326
|
+
rvm install jruby-9.2.13.0
|
325
327
|
```
|
326
328
|
|
327
|
-
Glimmer might still work on
|
329
|
+
Glimmer might still work on other versions of Java, JRuby and SWT, but there are no guarantees, so it is best to stick to the pre-requisites outlined above.
|
328
330
|
|
329
331
|
## Setup
|
330
332
|
|
@@ -332,16 +334,16 @@ Please follow these instructions to make the `glimmer` command available on your
|
|
332
334
|
|
333
335
|
If you intend to learn the basics of Glimmer but are not ready to build a Glimmer app yet, pick Option 1 ([Direct Install](#option-1-direct-install)).
|
334
336
|
|
335
|
-
If you intend to build a Glimmer app from scratch
|
337
|
+
If you intend to build a Glimmer app from scratch with [scaffolding](#scaffolding), pick Option 1 ([Direct Install](#option-1-direct-install)) as well.
|
336
338
|
|
337
|
-
Otherwise, Option 2 ([Bundler](#option-2-bundler))
|
339
|
+
Otherwise, Option 2 ([Bundler](#option-2-bundler)) can be followed in rare cases where you want to build an app without [scaffolding](#scaffolding).
|
338
340
|
|
339
341
|
### Option 1: Direct Install
|
340
|
-
(Use for [Scaffolding](#scaffolding)
|
342
|
+
(Use for [Scaffolding](#scaffolding))
|
341
343
|
|
342
344
|
Run this command to install directly:
|
343
345
|
```
|
344
|
-
jgem install glimmer-dsl-swt -v 0.
|
346
|
+
jgem install glimmer-dsl-swt -v 0.6.1
|
345
347
|
```
|
346
348
|
|
347
349
|
`jgem` is JRuby's version of `gem` command.
|
@@ -359,7 +361,7 @@ Note: if you're using activerecord or activesupport, keep in mind that Glimmer u
|
|
359
361
|
|
360
362
|
Add the following to `Gemfile`:
|
361
363
|
```
|
362
|
-
gem 'glimmer-dsl-swt', '~> 0.
|
364
|
+
gem 'glimmer-dsl-swt', '~> 0.6.1'
|
363
365
|
```
|
364
366
|
|
365
367
|
And, then run:
|
@@ -375,7 +377,7 @@ You may learn more about other Glimmer related gems ([`glimmer-dsl-opal`](https:
|
|
375
377
|
|
376
378
|
The `glimmer` command allows you to run, scaffold, package, and list Glimmer applications/gems.
|
377
379
|
|
378
|
-
If you are new to Glimmer, you may read the Basic Usage section and skip the rest until you have gone through [Girb (Glimmer irb) Command](#girb-glimmer-irb-command), [Glimmer DSL Syntax](#glimmer-dsl-syntax), and [Samples](#samples).
|
380
|
+
If you are new to Glimmer, you may read the Basic Usage section and skip the rest until you have gone through [Girb (Glimmer irb) Command](#girb-glimmer-irb-command), [Glimmer GUI DSL Syntax](#glimmer-gui-dsl-syntax), and [Samples](#samples).
|
379
381
|
|
380
382
|
### Basic Usage
|
381
383
|
|
@@ -413,19 +415,20 @@ Either a single task or one or more applications may be specified.
|
|
413
415
|
When a task is specified, it runs via rake. Some tasks take arguments in square brackets.
|
414
416
|
|
415
417
|
Available tasks are below (you may also lookup by adding `require 'glimmer/rake_task'` in Rakefile and running rake -T):
|
416
|
-
glimmer list:
|
417
|
-
glimmer list:
|
418
|
-
glimmer list:
|
419
|
-
glimmer package
|
420
|
-
glimmer package:clean
|
421
|
-
glimmer package:config
|
422
|
-
glimmer package:jar
|
423
|
-
glimmer package:
|
424
|
-
glimmer
|
425
|
-
glimmer scaffold
|
426
|
-
glimmer scaffold:
|
427
|
-
glimmer scaffold:
|
428
|
-
glimmer scaffold:
|
418
|
+
glimmer list:gems:customshell[query] # List Glimmer custom shell gems available at rubygems.org (query is optional) [alt: list:gems:cs]
|
419
|
+
glimmer list:gems:customwidget[query] # List Glimmer custom widget gems available at rubygems.org (query is optional) [alt: list:gems:cw]
|
420
|
+
glimmer list:gems:dsl[query] # List Glimmer DSL gems available at rubygems.org (query is optional)
|
421
|
+
glimmer package[type] # Package app for distribution (generating config, jar, and native files) (type is optional)
|
422
|
+
glimmer package:clean # Clean by removing "dist" and "packages" directories
|
423
|
+
glimmer package:config # Generate JAR config file
|
424
|
+
glimmer package:jar # Generate JAR file
|
425
|
+
glimmer package:lock_jars # Lock JARs
|
426
|
+
glimmer package:native[type] # Generate Native files (DMG/PKG/APP on the Mac, MSI/EXE/IMAGE on Windows, RPM/DEB on Linux) (type is optional)
|
427
|
+
glimmer scaffold[app_name] # Scaffold Glimmer application directory structure to build a new app
|
428
|
+
glimmer scaffold:customshell[name,namespace] # Scaffold Glimmer::UI::CustomShell subclass (full window view) under app/views (namespace is optional) [alt: scaffold:cs]
|
429
|
+
glimmer scaffold:customwidget[name,namespace] # Scaffold Glimmer::UI::CustomWidget subclass (part of a view) under app/views (namespace is optional) [alt: scaffold:cw]
|
430
|
+
glimmer scaffold:gem:customshell[name,namespace] # Scaffold Glimmer::UI::CustomShell subclass (full window view) under its own Ruby gem + app project (namespace is required) [alt: scaffold:gem:cs]
|
431
|
+
glimmer scaffold:gem:customwidget[name,namespace] # Scaffold Glimmer::UI::CustomWidget subclass (part of a view) under its own Ruby gem project (namespace is required) [alt: scaffold:gem:cw]
|
429
432
|
|
430
433
|
When applications are specified, they are run using JRuby,
|
431
434
|
automatically preloading the glimmer Ruby gem and SWT jar dependency.
|
@@ -467,7 +470,7 @@ getting you to a running and delivered state of an advanced "Hello, World!" Glim
|
|
467
470
|
This should greatly facilitate building a new Glimmer app by helping you be productive and focus on app details while
|
468
471
|
letting Glimmer scaffolding take care of initial app file structure concerns, such as adding:
|
469
472
|
- Main application class that includes Glimmer
|
470
|
-
- Main application view that houses main window content, about dialog, and preferences dialog
|
473
|
+
- Main application view that houses main window content, menu, about dialog, and preferences dialog
|
471
474
|
- View and Model directories
|
472
475
|
- Rakefile including Glimmer tasks
|
473
476
|
- Version
|
@@ -475,7 +478,7 @@ letting Glimmer scaffolding take care of initial app file structure concerns, su
|
|
475
478
|
- Icon
|
476
479
|
- Bin file for starting application
|
477
480
|
|
478
|
-
NOTE: Scaffolding
|
481
|
+
NOTE: Scaffolding supports Mac and Windows packaging at the moment.
|
479
482
|
|
480
483
|
#### App
|
481
484
|
|
@@ -511,20 +514,35 @@ Created CarMaker/bin/car_maker
|
|
511
514
|
...
|
512
515
|
```
|
513
516
|
|
514
|
-
Eventually, it will launch an advanced "Hello, World!" app window having the title of your application
|
517
|
+
Eventually, it will launch an advanced "Hello, World!" app window having the title of your application.
|
515
518
|
|
516
519
|
![Glimmer Scaffold App](images/glimmer-scaffolding-app.png)
|
517
520
|
|
518
|
-
|
521
|
+
It also comes with a boilerplate Preferences dialog.
|
519
522
|
|
520
523
|
![Glimmer Scaffold App Preferences](images/glimmer-scaffolding-app-preferences.png)
|
521
524
|
|
525
|
+
Here is a Windows scaffolded app called Greeter:
|
526
|
+
|
527
|
+
![Glimmer Scaffold App Windows](images/glimmer-scaffolding-app-windows.png)
|
528
|
+
|
529
|
+
Here is the Windows version of the boilerplate Preferences dialog.
|
530
|
+
|
531
|
+
![Glimmer Scaffold App Windows Preferences](images/glimmer-scaffolding-app-windows-preferences.png)
|
532
|
+
|
533
|
+
|
522
534
|
#### Custom Shell
|
523
535
|
|
524
536
|
To scaffold a Glimmer custom shell (full window view) for an existing Glimmer app, run the following command:
|
525
537
|
|
526
538
|
```
|
527
|
-
glimmer scaffold:
|
539
|
+
glimmer scaffold:customshell[name]
|
540
|
+
```
|
541
|
+
|
542
|
+
Or the following alternative abbreviation:
|
543
|
+
|
544
|
+
```
|
545
|
+
glimmer scaffold:cs[name]
|
528
546
|
```
|
529
547
|
|
530
548
|
#### Custom Widget
|
@@ -532,13 +550,19 @@ glimmer scaffold:custom_shell[custom_shell_name]
|
|
532
550
|
To scaffold a Glimmer custom widget (part of a view) for an existing Glimmer app, run the following command:
|
533
551
|
|
534
552
|
```
|
535
|
-
glimmer scaffold:
|
553
|
+
glimmer scaffold:customwidget[name]
|
554
|
+
```
|
555
|
+
|
556
|
+
Or the following alternative abbreviation:
|
557
|
+
|
558
|
+
```
|
559
|
+
glimmer scaffold:cw[name]
|
536
560
|
```
|
537
561
|
|
538
562
|
#### Custom Shell Gem
|
539
563
|
|
540
564
|
Custom shell gems are self-contained Glimmer apps as well as reusable custom shells.
|
541
|
-
They have everything scaffolded Glimmer apps come with in addition to gem content like a
|
565
|
+
They have everything scaffolded Glimmer apps come with in addition to gem content like a [jeweler](https://github.com/technicalpickles/jeweler) Rakefile that can build gemspec and release gems.
|
542
566
|
Unlike scaffolded Glimmer apps, custom shell gem content lives under the `lib` directory (not `app`).
|
543
567
|
They can be packaged as both a native executable (e.g. Mac DMG/PKG/APP) and a Ruby gem.
|
544
568
|
Of course, you can just build a Ruby gem and disregard native executable packaging if you do not need it.
|
@@ -546,7 +570,13 @@ Of course, you can just build a Ruby gem and disregard native executable packagi
|
|
546
570
|
To scaffold a Glimmer custom shell gem (full window view distributed as a Ruby gem), run the following command:
|
547
571
|
|
548
572
|
```
|
549
|
-
glimmer scaffold:
|
573
|
+
glimmer scaffold:gem:customshell[name,namespace]
|
574
|
+
```
|
575
|
+
|
576
|
+
Or the following alternative abbreviation:
|
577
|
+
|
578
|
+
```
|
579
|
+
glimmer scaffold:gem:cs[name,namespace]
|
550
580
|
```
|
551
581
|
|
552
582
|
It is important to specify a namespace to avoid having your gem clash with existing gems.
|
@@ -565,9 +595,16 @@ Examples:
|
|
565
595
|
To scaffold a Glimmer custom widget gem (part of a view distributed as a Ruby gem), run the following command:
|
566
596
|
|
567
597
|
```
|
568
|
-
glimmer scaffold:
|
598
|
+
glimmer scaffold:gem:customwidget[name,namespace]
|
599
|
+
```
|
600
|
+
|
601
|
+
Or the following alternative abbreviation:
|
602
|
+
|
603
|
+
```
|
604
|
+
glimmer scaffold:gem:cw[name,namespace]
|
569
605
|
```
|
570
606
|
|
607
|
+
|
571
608
|
It is important to specify a namespace to avoid having your gem clash with existing gems.
|
572
609
|
|
573
610
|
The Ruby gem name will follow the convention "glimmer-cw-customwidgetname-namespace" (the 'cw' is for Custom Widget)
|
@@ -588,13 +625,19 @@ The `glimmer` command comes with tasks for listing Glimmer related gems to make
|
|
588
625
|
The following command lists available Glimmer [Custom Shell Gems](#custom-shell-gem) (prefixed with "glimmer-cs-" by scaffolding convention) created by the the Glimmer community and published on [rubygems.org](http://www.rubygems.org):
|
589
626
|
|
590
627
|
```
|
591
|
-
glimmer list:
|
628
|
+
glimmer list:gems:customshell[query]
|
629
|
+
```
|
630
|
+
|
631
|
+
Or the following alternative abbreviation:
|
632
|
+
|
633
|
+
```
|
634
|
+
glimmer list:gems:cs[query]
|
592
635
|
```
|
593
636
|
|
594
637
|
Example:
|
595
638
|
|
596
639
|
```
|
597
|
-
glimmer list:
|
640
|
+
glimmer list:gems:cs
|
598
641
|
```
|
599
642
|
|
600
643
|
Output:
|
@@ -606,7 +649,7 @@ Output:
|
|
606
649
|
Name Gem Version Author Description
|
607
650
|
|
608
651
|
Calculator glimmer-cs-calculator 1.0.1 Andy Maleh Calculator - Glimmer Custom Shell
|
609
|
-
Gladiator glimmer-cs-gladiator 0.2.
|
652
|
+
Gladiator glimmer-cs-gladiator 0.2.3 Andy Maleh Gladiator (Glimmer Editor) - Glimmer Custom Shell
|
610
653
|
|
611
654
|
```
|
612
655
|
|
@@ -615,7 +658,13 @@ Output:
|
|
615
658
|
The following command lists available Glimmer [Custom Widget Gems](#custom-widget-gem) (prefixed with "glimmer-cw-" by scaffolding convention) created by the the Glimmer community and published on [rubygems.org](http://www.rubygems.org):
|
616
659
|
|
617
660
|
```
|
618
|
-
glimmer list:
|
661
|
+
glimmer list:gems:customwidget[query]
|
662
|
+
```
|
663
|
+
|
664
|
+
Or the following alternative abbreviation:
|
665
|
+
|
666
|
+
```
|
667
|
+
glimmer list:gems:cw[query]
|
619
668
|
```
|
620
669
|
|
621
670
|
Example:
|
@@ -623,7 +672,7 @@ Example:
|
|
623
672
|
Check if there is a custom video widget for Glimmer.
|
624
673
|
|
625
674
|
```
|
626
|
-
glimmer list:
|
675
|
+
glimmer list:gems:cw[video]
|
627
676
|
```
|
628
677
|
|
629
678
|
Output:
|
@@ -634,7 +683,7 @@ Output:
|
|
634
683
|
|
635
684
|
Name Gem Version Author Description
|
636
685
|
|
637
|
-
Video glimmer-cw-video 0.1.
|
686
|
+
Video glimmer-cw-video 0.1.3 Andy Maleh Glimmer Custom Widget - Video
|
638
687
|
|
639
688
|
```
|
640
689
|
|
@@ -643,13 +692,13 @@ Output:
|
|
643
692
|
The following command lists available Glimmer [DSL Gems](#multi-dsl-support) (prefixed with "glimmer-dsl-" by convention) created by the the Glimmer community and published on [rubygems.org](http://www.rubygems.org):
|
644
693
|
|
645
694
|
```
|
646
|
-
glimmer list:
|
695
|
+
glimmer list:gems:dsl[query]
|
647
696
|
```
|
648
697
|
|
649
698
|
Example:
|
650
699
|
|
651
700
|
```
|
652
|
-
glimmer list:
|
701
|
+
glimmer list:gems:dsl
|
653
702
|
```
|
654
703
|
|
655
704
|
Output:
|
@@ -660,10 +709,10 @@ Output:
|
|
660
709
|
|
661
710
|
Name Gem Version Author Description
|
662
711
|
|
663
|
-
Css glimmer-dsl-css 0.
|
664
|
-
Opal glimmer-dsl-opal 0.0
|
665
|
-
Swt glimmer-dsl-swt 0.
|
666
|
-
Xml glimmer-dsl-xml 0.
|
712
|
+
Css glimmer-dsl-css 0.2.0 AndyMaleh Glimmer DSL for CSS
|
713
|
+
Opal glimmer-dsl-opal 0.1.0 AndyMaleh Glimmer DSL for Opal
|
714
|
+
Swt glimmer-dsl-swt 0.6.1 AndyMaleh Glimmer DSL for SWT
|
715
|
+
Xml glimmer-dsl-xml 0.2.0 AndyMaleh Glimmer DSL for XML
|
667
716
|
|
668
717
|
```
|
669
718
|
|
@@ -716,13 +765,24 @@ Watch out for hands-on examples in this README indicated by "you may copy/paste
|
|
716
765
|
|
717
766
|
Keep in mind that all samples live under [https://github.com/AndyObtiva/glimmer-dsl-swt](https://github.com/AndyObtiva/glimmer-dsl-swt)
|
718
767
|
|
719
|
-
## Glimmer DSL Syntax
|
768
|
+
## Glimmer GUI DSL Syntax
|
720
769
|
|
721
|
-
Glimmer DSL
|
770
|
+
Glimmer is mainly a GUI DSL with a lightweight visual syntax that makes it easy to visualize the nesting of widgets in the GUI hierarchy tree.
|
722
771
|
|
723
|
-
|
772
|
+
The GUI DSL intentionally avoids overly verbose syntax, requiring as little declarative code as possible to describe what GUI to render, how to style it, and what properties to data-bind to the Models.
|
724
773
|
|
725
|
-
|
774
|
+
As such, it breaks off from Ruby's convention of using `do end` for multi-line blocks, opting instead for the lightweight and visual `{ }` curly brace blocks everywhere inside the GUI DSL. More details about Glimmer's syntax conventions may be found in the [Glimmer Style Guide](#glimmer-style-guide)
|
775
|
+
|
776
|
+
Glimmer DSL syntax consists mainly of:
|
777
|
+
- keywords (e.g. `table` for a table widget)
|
778
|
+
- style/args (e.g. :multi as in `table(:multi)` for a multi-line selection table widget)
|
779
|
+
- content (e.g. `{ table_column { text 'Name'} }` as in `table(:multi) { table_column { text 'name'} }` for a multi-line selection table widget with a table column having header text property `'Name'` as content)
|
780
|
+
|
781
|
+
Glimmer keywords may be static or dynamic.
|
782
|
+
|
783
|
+
Static keywords are pre-identified keywords in the Glimmer DSL, such as `shell`, `display`, `message_box`, `async_exec`, `sync_exec`, and `bind`.
|
784
|
+
|
785
|
+
Dynamic keywords are dynamically figured out from currently imported (aka required/loaded) SWT widgets, custom widgets, and widget properties. Examples are: `label`, `combo`, and `list` for widgets and `enabled`, `text`, and `selection` for properties.
|
726
786
|
|
727
787
|
The only reason to distinguish between the two types of Glimmer DSL keywords is to realize that importing new Glimmer [custom widgets](#custom-widgets) and Java SWT custom widget libraries automatically expands Glimmer's DSL vocabulary via new dynamic keywords.
|
728
788
|
|
@@ -742,9 +802,9 @@ https://www.eclipse.org/swt/widgets/
|
|
742
802
|
|
743
803
|
This screenshot taken from the link above should give a glimpse of how SWT widgets look and feel:
|
744
804
|
|
745
|
-
![SWT Widgets](images/glimmer-swt-widgets.png)
|
805
|
+
[![SWT Widgets](images/glimmer-swt-widgets.png)](https://www.eclipse.org/swt/widgets/)
|
746
806
|
|
747
|
-
In Glimmer DSL, widgets are declared with lowercase underscored names mirroring their SWT names minus the package name:
|
807
|
+
In Glimmer DSL, widgets are declared with lowercase underscored names mirroring their SWT names minus the package name. For example, here are some Glimmer widgets and their SWT counterparts:
|
748
808
|
|
749
809
|
- `shell` instantiates `org.eclipse.swt.widgets.Shell`
|
750
810
|
- `text` instantiates `org.eclipse.swt.widgets.Text`
|
@@ -760,8 +820,8 @@ In Glimmer DSL, widgets are declared with lowercase underscored names mirroring
|
|
760
820
|
- `list` instantiates `org.eclipse.swt.widgets.List`
|
761
821
|
|
762
822
|
Every **widget** is sufficiently declared by name, but may optionally be accompanied with:
|
763
|
-
- SWT **style
|
764
|
-
- Ruby block containing **properties** (
|
823
|
+
- SWT **style**/***arguments*** wrapped by parenthesis according to [Glimmer Style Guide](#glimmer-style-guide) (see [next section](#widget-styles) for details).
|
824
|
+
- Ruby block containing **content**, which may be **properties** (e.g. `enabled false`) or nested **widgets** (e.g. `table_column` nested inside `table`)
|
765
825
|
|
766
826
|
For example, if we were to revisit `samples/hello/hello_world.rb` above (you may copy/paste in [`girb`](#girb-glimmer-irb-command)):
|
767
827
|
|
@@ -843,6 +903,8 @@ shell {
|
|
843
903
|
}.open
|
844
904
|
```
|
845
905
|
|
906
|
+
If you are new to Glimmer, you have learned enough to start running some [samples](#samples). Go ahead and run all Glimmer [samples](#samples), and come back to read the rest in any order you like since this material is more organized like a reference.
|
907
|
+
|
846
908
|
#### Display
|
847
909
|
|
848
910
|
SWT Display is a singleton in Glimmer. It is used in SWT to represent your display device, allowing you to manage GUI globally
|
@@ -930,6 +992,21 @@ include Glimmer
|
|
930
992
|
@shell.open
|
931
993
|
```
|
932
994
|
|
995
|
+
![Hello Message Box Dialog](images/glimmer-hello-message-box-dialog.png)
|
996
|
+
|
997
|
+
It is also possible to use `message_box` even before instantiating the first `shell` ([Glimmer](https://rubygems.org/gems/glimmer) builds a throwaway `shell` parent automatically for it):
|
998
|
+
|
999
|
+
Example (you may copy/paste in [`girb`](#girb-glimmer-irb-command)):
|
1000
|
+
|
1001
|
+
```ruby
|
1002
|
+
include Glimmer
|
1003
|
+
|
1004
|
+
message_box {
|
1005
|
+
text 'Greeting'
|
1006
|
+
message "Hello, World!"
|
1007
|
+
}.open
|
1008
|
+
```
|
1009
|
+
|
933
1010
|
##### `#swt_widget`
|
934
1011
|
|
935
1012
|
Glimmer widget objects come with an instance method `#swt_widget` that returns the actual SWT `Widget` object wrapped by the Glimmer widget object. It is useful in cases you'd like to do some custom SWT programming outside of Glimmer.
|
@@ -949,6 +1026,24 @@ Shell widget proxy has extra methods specific to SWT Shell:
|
|
949
1026
|
- `#pack`: Packs contained widgets using SWT's `Shell#pack` method
|
950
1027
|
- `#pack_same_size`: Packs contained widgets without changing shell's size when widget sizes change
|
951
1028
|
|
1029
|
+
##### Shell Icon
|
1030
|
+
|
1031
|
+
To set the shell icon, simply set the `image` property under the `shell` widget. This shows up in the operating system toolbar and app-switcher (e.g. CMD+TAB) (and application window top-left corner in Windows)
|
1032
|
+
|
1033
|
+
Example:
|
1034
|
+
|
1035
|
+
```ruby
|
1036
|
+
shell {
|
1037
|
+
# ...
|
1038
|
+
image 'path/to/image.png'
|
1039
|
+
# ...
|
1040
|
+
}
|
1041
|
+
```
|
1042
|
+
|
1043
|
+
###### Shell Icon Tip for Packaging on Windows
|
1044
|
+
|
1045
|
+
When setting shell icon for a [packaged](#packaging--distribution) app, which has a JAR file at its core, you can reference the `ico` file that ships with the app by going one level up (e.g. `'../AppName.ico'`)
|
1046
|
+
|
952
1047
|
#### Dialog
|
953
1048
|
|
954
1049
|
Dialog is a variation on Shell. It is basically a shell that is modal (blocks what's behind it) and belongs to another shell. It only has a close button.
|
@@ -1124,7 +1219,7 @@ text(:center, :border) { # Multiple SWT styles separated by comma
|
|
1124
1219
|
Glimmer ships with SWT style **smart defaults** so you wouldn't have to set them yourself most of the time (albeit you can always override them):
|
1125
1220
|
|
1126
1221
|
- `text(:border)`
|
1127
|
-
- `table(:border)`
|
1222
|
+
- `table(:border, :virtual, :full_selection)`
|
1128
1223
|
- `tree(:border, :virtual, :v_scroll, :h_scroll)`
|
1129
1224
|
- `spinner(:border)`
|
1130
1225
|
- `list(:border, :v_scroll)`
|
@@ -1200,7 +1295,7 @@ button {
|
|
1200
1295
|
|
1201
1296
|
In the above example, the `text` widget `enabled` property was data-bound to `#empty` method on `@tic_tac_toe_board.box(row, column)` (learn more about data-binding below)
|
1202
1297
|
|
1203
|
-
####
|
1298
|
+
#### Color
|
1204
1299
|
|
1205
1300
|
Colors make up a subset of widget properties. SWT accepts color objects created with RGB (Red Green Blue) or RGBA (Red Green Blue Alpha). Glimmer supports constructing color objects using the `rgb` and `rgba` DSL keywords.
|
1206
1301
|
|
@@ -1249,7 +1344,7 @@ Example:
|
|
1249
1344
|
color(:black).swt_color # returns SWT Color object
|
1250
1345
|
```
|
1251
1346
|
|
1252
|
-
####
|
1347
|
+
#### Font
|
1253
1348
|
|
1254
1349
|
Fonts are represented in Glimmer as a hash of name, height, and style keys.
|
1255
1350
|
|
@@ -1278,7 +1373,34 @@ label {
|
|
1278
1373
|
# ...
|
1279
1374
|
```
|
1280
1375
|
|
1281
|
-
|
1376
|
+
You may simply use the standalone `font` keyword without nesting in a parent if there is a need to build a Font object to use in manual SWT programming outside of widget font property setting.
|
1377
|
+
|
1378
|
+
Example:
|
1379
|
+
|
1380
|
+
```ruby
|
1381
|
+
@font = font(name: 'Arial', height: 36, style: :normal)
|
1382
|
+
```
|
1383
|
+
|
1384
|
+
### Cursor
|
1385
|
+
|
1386
|
+
SWT widget `cursor` property represents the mouse cursor you see on the screen when you hover over that widget.
|
1387
|
+
|
1388
|
+
The `Display` class provides a way to obtain standard system cursors matching of the SWT style constants starting with prefix `CURSOR_` (e.g. `SWT::CURSOR_HELP` shows a question mark mouse cursor)
|
1389
|
+
|
1390
|
+
Glimmer provides an easier way to obtain and set `cursor` property on a widget by simply mentioning the SWT style constant as an abbreviated symbol excluding the "CURSOR_" suffix.
|
1391
|
+
|
1392
|
+
Example:
|
1393
|
+
|
1394
|
+
```ruby
|
1395
|
+
shell {
|
1396
|
+
minimum_size 128, 128
|
1397
|
+
cursor :appstarting
|
1398
|
+
}
|
1399
|
+
```
|
1400
|
+
|
1401
|
+
This sets the shell `cursor` to that of `SWT::CURSOR_APPSTARTING`
|
1402
|
+
|
1403
|
+
### Layout
|
1282
1404
|
|
1283
1405
|
Glimmer lays widgets out visually using SWT layouts, which can only be set on composite widget and subclasses.
|
1284
1406
|
|
@@ -1840,7 +1962,8 @@ Let's revisit the Tic Tac Toe example shown near the beginning of the page:
|
|
1840
1962
|
```ruby
|
1841
1963
|
shell {
|
1842
1964
|
text "Tic-Tac-Toe"
|
1843
|
-
|
1965
|
+
minimum_size 150, 178
|
1966
|
+
composite {
|
1844
1967
|
grid_layout 3, true
|
1845
1968
|
(1..3).each { |row|
|
1846
1969
|
(1..3).each { |column|
|
@@ -2542,11 +2665,9 @@ Glimmer configuration may be done via the `Glimmer::Config` module.
|
|
2542
2665
|
|
2543
2666
|
### logger
|
2544
2667
|
|
2545
|
-
Glimmer supports logging via a standard `STDOUT` Ruby `Logger` configured in the `Glimmer::Config.logger` config option.
|
2668
|
+
The Glimmer DSL engine supports logging via a standard `STDOUT` Ruby `Logger` configured in the `Glimmer::Config.logger` config option.
|
2546
2669
|
It is set to level Logger::ERROR by default.
|
2547
2670
|
Log level may be adjusted via `Glimmer::Config.logger.level` just like any other Ruby Logger.
|
2548
|
-
It may be replaced with a custom logger via `Glimmer::Config.logger = custom_logger`
|
2549
|
-
All logging is done lazily via blocks (e.g. `logger.debug {message}`) to avoid affecting app performance with logging when below the configured logging level threshold.
|
2550
2671
|
|
2551
2672
|
Example:
|
2552
2673
|
|
@@ -2571,6 +2692,55 @@ D, [2017-07-21T19:23:12.878434 #35707] DEBUG -- : WidgetCommandHandler will hand
|
|
2571
2692
|
D, [2017-07-21T19:23:12.878798 #35707] DEBUG -- : widget styles are: [:multi]
|
2572
2693
|
```
|
2573
2694
|
|
2695
|
+
The `logger` instance may be replaced with a custom logger via `Glimmer::Config.logger = custom_logger`
|
2696
|
+
|
2697
|
+
To reset `logger` to the default instance, you may call `Glimmer::Config.reset_logger!`
|
2698
|
+
|
2699
|
+
All logging is done lazily via blocks (e.g. `logger.debug {message}`) to avoid affecting app performance with logging when below the configured logging level threshold.
|
2700
|
+
|
2701
|
+
[Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt) enhances Glimmer default logging support via the Ruby [`logging`](https://github.com/TwP/logging) gem, enabling buffered asynchronous logging in a separate thread, thus completely unhindering normal desktop app performance.
|
2702
|
+
|
2703
|
+
Other config options related to the [`logging`](https://github.com/TwP/logging) gem are mentioned below.
|
2704
|
+
|
2705
|
+
#### logging_devices
|
2706
|
+
|
2707
|
+
This is an array of these possible values: `:stdout` (default), `:stderr`, `:file`, `:syslog` (default), `:stringio`
|
2708
|
+
|
2709
|
+
It defaults to `[:stdout, :syslog]`
|
2710
|
+
|
2711
|
+
When `:file` is included, Glimmer creates a 'log' directory directly below the Glimmer app local directory.
|
2712
|
+
It may also be customized further via the `logging_device_file_options` option.
|
2713
|
+
This is useful on Windows as an alternative to `syslog`, which is not available on Windows by default.
|
2714
|
+
|
2715
|
+
#### logging_device_file_options
|
2716
|
+
|
2717
|
+
This is a hash of [`logging`](https://github.com/TwP/logging) gem options for the `:file` logging device.
|
2718
|
+
|
2719
|
+
Default: `{size: 1_000_000, age: 'daily', roll_by: 'number'}`
|
2720
|
+
|
2721
|
+
That ensures splitting log files at the 1MB size and daily, rolling them by unique number.
|
2722
|
+
|
2723
|
+
#### logging_appender_options
|
2724
|
+
|
2725
|
+
Appender options is a hash passed as options to every appender (logging device) used in the [`logging`](https://github.com/TwP/logging) gem.
|
2726
|
+
|
2727
|
+
Default: `{async: true, auto_flushing: 500, write_size: 500, flush_period: 60, immediate_at: [:error, :fatal], layout: logging_layout}`
|
2728
|
+
|
2729
|
+
That ensures asynchronous buffered logging that is flushed every 500 messages and 60 seconds, or immediately at error and fatal log levels
|
2730
|
+
|
2731
|
+
#### logging_layout
|
2732
|
+
|
2733
|
+
This is a [`logging`](https://github.com/TwP/logging) gem layout that formats the logging output.
|
2734
|
+
|
2735
|
+
Default:
|
2736
|
+
|
2737
|
+
```
|
2738
|
+
Logging.layouts.pattern(
|
2739
|
+
pattern: '[%d] %-5l %c: %m\n',
|
2740
|
+
date_pattern: '%Y-%m-%d %H:%M:%S'
|
2741
|
+
)
|
2742
|
+
```
|
2743
|
+
|
2574
2744
|
### import_swt_packages
|
2575
2745
|
|
2576
2746
|
Glimmer automatically imports all SWT Java packages upon adding `include Glimmer`, `include Glimmer::UI::CustomWidget`, or `include Glimmer::UI::CustomShell` to a class or module. It relies on JRuby's `include_package` for lazy-importing upon first reference of a Java class.
|
@@ -2920,6 +3090,8 @@ This sample demonstrates a full MVC application, including GUI layout, text and
|
|
2920
3090
|
|
2921
3091
|
Code:
|
2922
3092
|
|
3093
|
+
(Please note that on some Linux instances where the display x-axis is set to double-scale, you need to set the `shell` `minimum_size` to `300, 178` instead of `150, 178`)
|
3094
|
+
|
2923
3095
|
[samples/elaborate/tic_tac_toe.rb](https://github.com/AndyObtiva/glimmer-dsl-swt/blob/master/samples/elaborate/tic_tac_toe.rb)
|
2924
3096
|
|
2925
3097
|
Run:
|
@@ -2995,6 +3167,8 @@ Gladiator is a good demonstration of:
|
|
2995
3167
|
|
2996
3168
|
The following production apps have been built with Glimmer.
|
2997
3169
|
|
3170
|
+
If you have a Glimmer app you would like referenced here, please mention in a Pull Request.
|
3171
|
+
|
2998
3172
|
### Math Bowling
|
2999
3173
|
|
3000
3174
|
[<img alt="Math Bowling Logo" src="https://raw.githubusercontent.com/AndyObtiva/MathBowling/master/images/math-bowling-logo.png" width="40" />Math Bowling](https://github.com/AndyObtiva/MathBowling): an educational math game for elementary level kids
|
@@ -3003,20 +3177,30 @@ The following production apps have been built with Glimmer.
|
|
3003
3177
|
|
3004
3178
|
[<img alt="Are We There Yet Logo" src="https://raw.githubusercontent.com/AndyObtiva/are-we-there-yet/master/are-we-there-yet-logo.svg" width="40" />Are We There Yet?](https://github.com/AndyObtiva/are-we-there-yet): A tool that helps you learn when your small projects will finish
|
3005
3179
|
|
3006
|
-
|
3180
|
+
### Garderie Rainbow Daily Agenda
|
3181
|
+
|
3182
|
+
[<img alt="Garderie Rainbow Daily Agenda Logo" src="https://github.com/AndyObtiva/garderie_rainbow_daily_agenda/raw/master/images/garderie_rainbow_daily_agenda_logo.png" width="40" />Garderie Rainbow Daily Agenda](https://github.com/AndyObtiva/garderie_rainbow_daily_agenda): A child nursery daily agenda reporting desktop app
|
3007
3183
|
|
3008
3184
|
## Packaging & Distribution
|
3009
3185
|
|
3010
3186
|
Glimmer apps may be packaged and distributed on the Mac, Windows, and Linux via these tools:
|
3011
3187
|
- Warbler (https://github.com/jruby/warbler): Enables bundling a Glimmer app into a JAR file
|
3012
|
-
- javapackager (https://docs.oracle.com/javase/8/docs/technotes/tools/unix/javapackager.html): Enables packaging a JAR file as a DMG file on Mac, EXE on Windows, and
|
3188
|
+
- javapackager (https://docs.oracle.com/javase/8/docs/technotes/tools/unix/javapackager.html): Enables packaging a JAR file as a DMG/PKG/APP file on Mac, MSI/EXE on Windows, and DEB/RPM on Linux.
|
3013
3189
|
|
3014
|
-
Glimmer simplifies the process of Mac packaging via the `glimmer package` command
|
3190
|
+
Glimmer simplifies the process of Mac and Windows packaging via the `glimmer package` command:
|
3015
3191
|
|
3016
3192
|
```
|
3017
3193
|
glimmer package
|
3018
3194
|
```
|
3019
3195
|
|
3196
|
+
It works out of the box for any application generated by [Glimmer Scaffolding](#scaffolding).
|
3197
|
+
|
3198
|
+
Otherwise, if you are using Glimmer manually, to make the `glimmer package` command available, you must add the following line to your application `Rakefile`:
|
3199
|
+
|
3200
|
+
```ruby
|
3201
|
+
require 'glimmer/rake_task'
|
3202
|
+
```
|
3203
|
+
|
3020
3204
|
This will automatically generate a JAR file under `./dist` directory using Warbler, which is then used to automatically generate a DMG file (and pkg/app) under `./packages/bundles` using `javapackager`.
|
3021
3205
|
JAR file name will match your application local directory name (e.g. `MathBowling.jar` for `~/code/MathBowling`)
|
3022
3206
|
DMG file name will match the humanized local directory name + dash + application version (e.g. `Math Bowling-1.0.dmg` for `~/code/MathBowling` with version 1.0 or unspecified)
|
@@ -3024,6 +3208,14 @@ DMG file name will match the humanized local directory name + dash + application
|
|
3024
3208
|
The `glimmer package` command will automatically set "mac.CFBundleIdentifier" to ="org.#{project_name}.application.#{project_name}".
|
3025
3209
|
You may override by configuring as an extra argument for javapackger (e.g. Glimmer::Package.javapackager_extra_args = " -Bmac.CFBundleIdentifier=org.andymaleh.application.MathBowling")
|
3026
3210
|
|
3211
|
+
You may choose to generate a specific type of packaging by passing the `[type]` option:
|
3212
|
+
|
3213
|
+
```
|
3214
|
+
glimmer package[msi]
|
3215
|
+
```
|
3216
|
+
|
3217
|
+
That generates an MSI file on Windows (could specify exe or image as alternatives on Windows).
|
3218
|
+
|
3027
3219
|
### Packaging Defaults
|
3028
3220
|
|
3029
3221
|
Glimmer employs smart defaults in packaging.
|
@@ -3084,6 +3276,14 @@ JAVAPACKAGER_EXTRA_ARGS='-Bmac.CFBundleName="Math Bowling Game"' glimmer package
|
|
3084
3276
|
|
3085
3277
|
That overrides the default application display name.
|
3086
3278
|
|
3279
|
+
### Windows Application Packaging
|
3280
|
+
|
3281
|
+
Windows offers two options for setup packaging:
|
3282
|
+
- `msi` (recommended): simpler packaging option. Requires [WiX Toolset](https://wixtoolset.org/) and [.NET Framework](https://dotnet.microsoft.com/download/dotnet-framework). Simply run `glimmer package[msi]` (or `glimmer package:native[msi]` if it's not your first time) and it will tell you what you need to install including which version of .NET Framework it needs.
|
3283
|
+
- `exe`: more advanced packaging option. Requires [Inno Setup](https://jrsoftware.org/isinfo.php). Simply run `glimmer package[exe]` (or `glimmer package:native[exe]` if it's not your first time) and it will tell you what you need to install.
|
3284
|
+
|
3285
|
+
If you just want to test out packaging into a native Windows app that is not packaged for Windows setup, just pass `image` to generate a native Windows app only.
|
3286
|
+
|
3087
3287
|
### Mac Application Distribution
|
3088
3288
|
|
3089
3289
|
Recent macOS versions (starting with Catalina) have very stringent security requirements requiring all applications to be signed before running (unless the user goes to System Preferences -> Privacy -> General tab and clicks "Open Anyway" after failing to open application the first time they run it). So, to release a desktop application on the Mac, it is recommended to enroll in the [Apple Developer Program](https://developer.apple.com/programs/) to distribute on the [Mac App Store](https://developer.apple.com/distribute/) or otherwise request [app notarization from Apple](https://developer.apple.com/documentation/xcode/notarizing_macos_software_before_distribution) to distribute independently.
|
@@ -3149,6 +3349,10 @@ By the way, keep in mind that during normal operation, it does also indicate a f
|
|
3149
3349
|
Exec failed with code 2 command [[/usr/bin/SetFile, -c, icnC, /var/folders/4_/g1sw__tx6mjdgyh3mky7vydc0000gp/T/fxbundler4076750801763032201/images/MathBowling/.VolumeIcon.icns] in unspecified directory
|
3150
3350
|
```
|
3151
3351
|
|
3352
|
+
## App Updates
|
3353
|
+
|
3354
|
+
Glimmer already supports automatic (and manual) app updates via the Mac App Store for Mac apps. Simply run the `glimmer package` command with the Mac App Store keys configured as per [Mac Application Distribution](mac-application-distribution) instructions and you get automatic (and manual) app update support courtesy of the Mac App Store.
|
3355
|
+
|
3152
3356
|
## Resources
|
3153
3357
|
|
3154
3358
|
* [Code Master Blog](http://andymaleh.blogspot.com/search/label/Glimmer)
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.10.
|
1
|
+
0.10.2
|
data/lib/glimmer.rb
CHANGED
data/lib/glimmer/config.rb
CHANGED
@@ -15,9 +15,7 @@ module Glimmer
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def reset_excluded_keyword_checkers!
|
18
|
-
@excluded_keyword_checkers = [
|
19
|
-
lambda { |method_symbol, *args| method_symbol.to_s.match(REGEX_METHODS_EXCLUDED) }
|
20
|
-
]
|
18
|
+
@excluded_keyword_checkers = [ lambda { |method_symbol, *args| method_symbol.to_s.match(REGEX_METHODS_EXCLUDED) } ]
|
21
19
|
end
|
22
20
|
|
23
21
|
def loop_max_count
|
@@ -25,7 +23,7 @@ module Glimmer
|
|
25
23
|
end
|
26
24
|
|
27
25
|
# Returns Glimmer logger (standard Ruby logger)
|
28
|
-
def logger
|
26
|
+
def logger
|
29
27
|
reset_logger! unless defined? @@logger
|
30
28
|
@@logger
|
31
29
|
end
|
@@ -36,13 +34,9 @@ module Glimmer
|
|
36
34
|
|
37
35
|
def reset_logger!
|
38
36
|
self.logger = Logger.new(STDOUT).tap do |logger|
|
39
|
-
logger.level = Logger::ERROR
|
37
|
+
logger.level = ENV['GLIMMER_LOGGER_LEVEL'] ? ENV['GLIMMER_LOGGER_LEVEL'].downcase : Logger::ERROR
|
40
38
|
end
|
41
39
|
end
|
42
40
|
end
|
43
41
|
end
|
44
42
|
end
|
45
|
-
|
46
|
-
if ENV['GLIMMER_LOGGER_LEVEL']
|
47
|
-
Glimmer::Config.logger.level = ENV['GLIMMER_LOGGER_LEVEL'].downcase
|
48
|
-
end
|
@@ -1,77 +1,280 @@
|
|
1
1
|
require 'set'
|
2
|
+
require 'array_include_methods'
|
2
3
|
|
3
4
|
require 'glimmer/data_binding/observable'
|
4
5
|
|
6
|
+
using ArrayIncludeMethods
|
7
|
+
|
5
8
|
module Glimmer
|
6
9
|
module DataBinding
|
7
10
|
# TODO prefix utility methods with double-underscore
|
8
11
|
module ObservableArray
|
9
12
|
include Observable
|
10
13
|
|
11
|
-
def add_observer(observer, element_properties
|
12
|
-
|
14
|
+
def add_observer(observer, *element_properties)
|
15
|
+
element_properties = element_properties.flatten.compact.uniq
|
16
|
+
return observer if has_observer?(observer) && has_observer_element_properties?(observer, element_properties)
|
13
17
|
property_observer_list << observer
|
14
|
-
[
|
15
|
-
|
16
|
-
observer.observe(element, property)
|
17
|
-
end
|
18
|
-
end
|
18
|
+
observer_element_properties[observer] = element_properties_for(observer) + Set.new(element_properties)
|
19
|
+
each { |element| add_element_observer(element, observer) }
|
19
20
|
observer
|
20
21
|
end
|
22
|
+
|
23
|
+
def add_element_observers(element)
|
24
|
+
property_observer_list.each do |observer|
|
25
|
+
add_element_observer(element, observer)
|
26
|
+
end
|
27
|
+
end
|
21
28
|
|
22
|
-
def
|
23
|
-
|
24
|
-
|
29
|
+
def add_element_observer(element, observer)
|
30
|
+
element_properties_for(observer).each do |property|
|
31
|
+
observer.observe(element, property)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def remove_observer(observer, *element_properties)
|
36
|
+
element_properties = element_properties.flatten.compact.uniq
|
37
|
+
if !element_properties.empty?
|
38
|
+
old_element_properties = element_properties_for(observer)
|
39
|
+
observer_element_properties[observer] = element_properties_for(observer) - Set.new(element_properties)
|
25
40
|
each do |element|
|
26
|
-
|
41
|
+
element_properties.each do |property|
|
42
|
+
observer.unobserve(element, property)
|
43
|
+
end
|
27
44
|
end
|
28
45
|
end
|
46
|
+
if element_properties_for(observer).empty?
|
47
|
+
property_observer_list.delete(observer)
|
48
|
+
observer_element_properties.delete(observer)
|
49
|
+
each { |element| remove_element_observer(element, observer) }
|
50
|
+
end
|
29
51
|
observer
|
30
52
|
end
|
31
53
|
|
54
|
+
def remove_element_observers(element)
|
55
|
+
property_observer_list.each do |observer|
|
56
|
+
remove_element_observer(element, observer)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def remove_element_observer(element, observer)
|
61
|
+
element_properties_for(observer).each do |property|
|
62
|
+
observer.unobserve(element, property)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
32
66
|
def has_observer?(observer)
|
33
67
|
property_observer_list.include?(observer)
|
34
68
|
end
|
69
|
+
|
70
|
+
def has_observer_element_properties?(observer, element_properties)
|
71
|
+
element_properties_for(observer).to_a.include_all?(element_properties)
|
72
|
+
end
|
35
73
|
|
36
74
|
def property_observer_list
|
37
75
|
@property_observer_list ||= Set.new
|
38
76
|
end
|
39
77
|
|
78
|
+
def observer_element_properties
|
79
|
+
@observer_element_properties ||= {}
|
80
|
+
end
|
81
|
+
|
82
|
+
def element_properties_for(observer)
|
83
|
+
observer_element_properties[observer] ||= Set.new
|
84
|
+
end
|
85
|
+
|
40
86
|
def notify_observers
|
41
87
|
property_observer_list.to_a.each(&:call)
|
42
88
|
end
|
43
89
|
|
44
90
|
def <<(element)
|
45
|
-
super(element)
|
46
|
-
|
91
|
+
super(element).tap do
|
92
|
+
add_element_observers(element)
|
93
|
+
notify_observers
|
94
|
+
end
|
47
95
|
end
|
96
|
+
alias push <<
|
48
97
|
|
49
98
|
def []=(index, value)
|
50
99
|
old_value = self[index]
|
51
100
|
unregister_dependent_observers(old_value)
|
52
|
-
|
53
|
-
|
101
|
+
remove_element_observers(old_value)
|
102
|
+
add_element_observers(value)
|
103
|
+
super(index, value).tap do
|
104
|
+
notify_observers
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def pop
|
109
|
+
popped_element = last
|
110
|
+
unregister_dependent_observers(popped_element)
|
111
|
+
remove_element_observers(popped_element)
|
112
|
+
super.tap do
|
113
|
+
notify_observers
|
114
|
+
end
|
54
115
|
end
|
55
116
|
|
56
117
|
def delete(element)
|
57
118
|
unregister_dependent_observers(element)
|
58
|
-
|
59
|
-
|
119
|
+
remove_element_observers(element)
|
120
|
+
super(element).tap do
|
121
|
+
notify_observers
|
122
|
+
end
|
60
123
|
end
|
61
124
|
|
62
125
|
def delete_at(index)
|
63
126
|
old_value = self[index]
|
64
127
|
unregister_dependent_observers(old_value)
|
65
|
-
|
66
|
-
|
128
|
+
remove_element_observers(old_value)
|
129
|
+
super(index).tap do
|
130
|
+
notify_observers
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def delete_if(&block)
|
135
|
+
if block_given?
|
136
|
+
old_array = Array.new(self)
|
137
|
+
super(&block).tap do |new_array|
|
138
|
+
(old_array - new_array).each do |element|
|
139
|
+
unregister_dependent_observers(element)
|
140
|
+
remove_element_observers(element)
|
141
|
+
end
|
142
|
+
notify_observers
|
143
|
+
end
|
144
|
+
else
|
145
|
+
super
|
146
|
+
end
|
67
147
|
end
|
68
148
|
|
69
149
|
def clear
|
70
150
|
each do |old_value|
|
71
151
|
unregister_dependent_observers(old_value)
|
152
|
+
remove_element_observers(old_value)
|
153
|
+
end
|
154
|
+
super.tap do
|
155
|
+
notify_observers
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def reverse!
|
160
|
+
super.tap do
|
161
|
+
notify_observers
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def collect!(&block)
|
166
|
+
if block_given?
|
167
|
+
each do |old_value|
|
168
|
+
unregister_dependent_observers(old_value)
|
169
|
+
remove_element_observers(old_value)
|
170
|
+
end
|
171
|
+
super(&block).tap do
|
172
|
+
each do |element|
|
173
|
+
add_element_observers(element)
|
174
|
+
end
|
175
|
+
notify_observers
|
176
|
+
end
|
177
|
+
else
|
178
|
+
super
|
179
|
+
end
|
180
|
+
end
|
181
|
+
alias map! collect!
|
182
|
+
|
183
|
+
def compact!
|
184
|
+
super.tap do
|
185
|
+
notify_observers
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def flatten!(level=nil)
|
190
|
+
each do |old_value|
|
191
|
+
unregister_dependent_observers(old_value)
|
192
|
+
remove_element_observers(old_value)
|
193
|
+
end
|
194
|
+
(level.nil? ? super() : super(level)).tap do
|
195
|
+
each do |element|
|
196
|
+
add_element_observers(element)
|
197
|
+
end
|
198
|
+
notify_observers
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def rotate!(count=1)
|
203
|
+
super(count).tap do
|
204
|
+
notify_observers
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def select!(&block)
|
209
|
+
if block_given?
|
210
|
+
old_array = Array.new(self)
|
211
|
+
super(&block).tap do
|
212
|
+
(old_array - self).each do |old_value|
|
213
|
+
unregister_dependent_observers(old_value)
|
214
|
+
remove_element_observers(old_value)
|
215
|
+
end
|
216
|
+
notify_observers
|
217
|
+
end
|
218
|
+
else
|
219
|
+
super
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def shuffle!(hash = nil)
|
224
|
+
(hash.nil? ? super() : super(random: hash[:random])).tap do
|
225
|
+
notify_observers
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
def slice!(arg1, arg2=nil)
|
230
|
+
old_array = Array.new(self)
|
231
|
+
(arg2.nil? ? super(arg1) : super(arg1, arg2)).tap do
|
232
|
+
(old_array - self).each do |old_value|
|
233
|
+
unregister_dependent_observers(old_value)
|
234
|
+
remove_element_observers(old_value)
|
235
|
+
end
|
236
|
+
notify_observers
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
def sort!(&block)
|
241
|
+
(block.nil? ? super() : super(&block)).tap do
|
242
|
+
notify_observers
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
def sort_by!(&block)
|
247
|
+
(block.nil? ? super() : super(&block)).tap do
|
248
|
+
notify_observers
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
def uniq!(&block)
|
253
|
+
each do |old_value|
|
254
|
+
unregister_dependent_observers(old_value)
|
255
|
+
remove_element_observers(old_value)
|
256
|
+
end
|
257
|
+
(block.nil? ? super() : super(&block)).tap do
|
258
|
+
each do |element|
|
259
|
+
add_element_observers(element)
|
260
|
+
end
|
261
|
+
notify_observers
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
def reject!(&block)
|
266
|
+
if block_given?
|
267
|
+
old_array = Array.new(self)
|
268
|
+
super(&block).tap do
|
269
|
+
(old_array - self).each do |old_value|
|
270
|
+
unregister_dependent_observers(old_value)
|
271
|
+
remove_element_observers(old_value)
|
272
|
+
end
|
273
|
+
notify_observers
|
274
|
+
end
|
275
|
+
else
|
276
|
+
super
|
72
277
|
end
|
73
|
-
super()
|
74
|
-
notify_observers
|
75
278
|
end
|
76
279
|
|
77
280
|
def unregister_dependent_observers(old_value)
|
@@ -59,6 +59,7 @@ module Glimmer
|
|
59
59
|
# registers observer in an observable on a property (optional)
|
60
60
|
# observer maintains registration list to unregister later
|
61
61
|
def register(observable, property = nil)
|
62
|
+
return if observable.nil?
|
62
63
|
unless observable.is_a?(Observable)
|
63
64
|
# TODO refactor code to be more smart/polymorphic/automated and honor open/closed principle
|
64
65
|
if observable.is_a?(Array)
|
metadata
CHANGED
@@ -1,15 +1,35 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: glimmer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.10.
|
4
|
+
version: 0.10.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- AndyMaleh
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-08-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - ">="
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: 1.0.2
|
19
|
+
- - "<"
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 2.0.0
|
22
|
+
name: array_include_methods
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.0.2
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 2.0.0
|
13
33
|
- !ruby/object:Gem::Dependency
|
14
34
|
requirement: !ruby/object:Gem::Requirement
|
15
35
|
requirements:
|