Skip to content

Commit

Permalink
Simplified sub mappings to widget constructors (#108)
Browse files Browse the repository at this point in the history
* Add :subs option, export subroutine aliases for widget constructors

Now when you do:

  use GTK::Simple :subs;

you can subsequently call the constructor of any widget via a simplified
version of it's name:

  my $button = button(label => "Shorter");
  my $list-box = list-box;
  my $file-chooser-button = file-chooser-button(label => "File?");

The pattern is a simple conversion from camel case to kebab case.
Delicious!

This also fixes the issue of needing to `use GTK::Simple::App;` on a
separate line. Now it is available immediately.

* In recognition of not needing 'use GTK::Simple::App'

* Add complete tests

* Update README

* Bump minor version. Use the same guard as existing tests

* Avoid a merge conflict with the test.yaml branch

* Whitespace change to trigger CI/CD
  • Loading branch information
ab5tract committed Feb 25, 2023
1 parent aeeb9d9 commit 4419b07
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 5 deletions.
2 changes: 1 addition & 1 deletion META6.json
@@ -1,7 +1,7 @@
{
"name": "GTK::Simple",
"description": "Simple GTK 3 binding using NativeCall",
"version": "0.2.4",
"version": "0.3.0",
"perl": "6.d",
"authors": [
"Jonathan Worthington",
Expand Down
30 changes: 28 additions & 2 deletions README.md
Expand Up @@ -4,6 +4,7 @@
GTK::Simple is a set of simple [GTK 3](http://www.gtk.org/) bindings using
NativeCall. Only some GTK widgets are currently implemented. However, these are
enough to create a reasonable interactive GUI for an idiomatic Raku program.

The GTK Widgets in this distribution include the following:

Widget | Description
Expand Down Expand Up @@ -43,7 +44,6 @@ VBox, HBox | Widget containers which enable window layout design

```raku
use GTK::Simple;
use GTK::Simple::App;

my $app = GTK::Simple::App.new( title => "Hello GTK!" );

Expand All @@ -61,14 +61,40 @@ $second.clicked.tap({ $app.exit; });
$app.run;
```

### Using :subs option

Another approach is to specify `:subs` on import. This provides subroutine aliases for the constructors
of all of the available `GTK::Simple` widgets, converted from CamelCase to kebab-case.

`GTK::Simple::MenuToolButton` becomes `menu-tool-button`, `GTK::Simple::ProgressBar` becomes `progress-bar`, etc.

The above example can be equivalently written as:

```raku
use GTK::Simple :subs;

my $app = app(title => "Hello GTK!");

$app.set-content(
v-box(
my $button1 = button(label => "Hello World"),
my $button2 = button(label => "Goodbye!")
)
);

# ...
```

### Further examples

The first four examples were written as mini tutorials to show how the
system works:
- [Hello world](https://github.com/finanalyst/GTK-Simple/blob/master/examples/01-hello-world.raku)
- [Toggles](https://github.com/finanalyst/GTK-Simple/blob/master/examples/02-toggles.raku)
- [A simple grid](https://github.com/finanalyst/GTK-Simple/blob/master/examples/03-grid.raku)
- [Marked Scales](https://github.com/finanalyst/GTK-Simple/blob/master/examples/04-marked-scale.raku)

For more examples, please see the [`examples/`](https://github.com/finanalyst/GTK-Simple/blob/master/examples) folder.
For more examples, please see the [examples/](https://github.com/finanalyst/GTK-Simple/blob/master/examples) folder.

## Limitations

Expand Down
12 changes: 11 additions & 1 deletion lib/GTK/Simple.rakumod
@@ -1,6 +1,8 @@

use v6;

unit module GTK::Simple;

need GTK::Simple::ConnectionHandler;
need GTK::Simple::Widget;
need GTK::Simple::Container;
Expand Down Expand Up @@ -41,4 +43,12 @@ need GTK::Simple::LinkButton;
need GTK::Simple::ScrolledWindow;
need GTK::Simple::Calendar;
need GTK::Simple::ListBox;
need GTK::Simple::CheckMenuItem;
need GTK::Simple::CheckMenuItem;

# Exports above class constructors, ex. level-bar => GTK::Simple::LevelBar.new
my module EXPORT::subs {
for GTK::Simple::.kv -> $name, $class {
my $sub-name = '&' ~ ($name ~~ / (<:Lu><:Ll>*)* /).values.map({ .Str.lc }).join("-");
OUR::{ $sub-name } := sub (|c) { $class.new(|c) };
}
}
1 change: 0 additions & 1 deletion t/01-sanity.rakutest
@@ -1,7 +1,6 @@
use v6;
use Test;
use GTK::Simple;
use GTK::Simple::App;
use GTK::Simple::Scheduler;

plan *;
Expand Down
31 changes: 31 additions & 0 deletions t/02-export-subs.rakutest
@@ -0,0 +1,31 @@
use v6.d;
use Test;

plan *;

use GTK::Simple :subs;

if %*ENV<DISPLAY> or $*DISTRO.is-win {
# We need to create app first
my $app;
lives-ok { $app = app }, "There is a subroutine in scope called 'app'";
ok $app ~~ GTK::Simple::App, "'app' returns a GTK::Simple::App object";

# Other modules are pulled into GTK::Simple namespace by now that we do not want to test
sub skip-test($name) {
state $skip-set = set '&' X~ <app simple raw native-lib g-d-k common property-facade>;
$name (elem) $skip-set
}

for GTK::Simple::.kv -> $name, $class {
my $sub-name = '&' ~ ($name ~~ / (<:Lu><:Ll>*)* /).values.map({ .Str.lc }).join("-");
next if skip-test($sub-name);

my $widget;
lives-ok { $widget = ::{$sub-name}(:label("For Button(s)"), :uri("For LinkButton")) },
"There is a subroutine in scope called '$sub-name'";
ok $widget ~~ $class, "'$sub-name' returns a { $class.^name } object";
}
}

done-testing;

0 comments on commit 4419b07

Please sign in to comment.