applin-rails 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +13 -0
- data/README.md +9 -5
- data/cla-email-template.txt +114 -0
- data/lib/applin/rails/version.rb +1 -1
- data/lib/applin/rails.rb +5 -193
- data/lib/applin.rb +218 -0
- data/sig/applin/rails.rbs +1 -2
- data/sig/applin.rbs +115 -0
- metadata +5 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7cdc30c31c59b934ab7a5592ca8c6e380025e19d9fd5d349eb50239cd86caf29
|
|
4
|
+
data.tar.gz: 303ed1586f7fa12a4b0ff4d8fb2b9db12671e503b73a556700aea0f2415207e3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 257fbad034bd0e46bbc2b122076ce3bfa4e0bd75db1bdec47dc6fec40473b36e9bbf89a2ab59ba91350fa71a340f0e3cb9b18394aaf734a2b71842dd1f3b3940
|
|
7
|
+
data.tar.gz: 16e60297df8d5d96f8ba089f6c01210a860fa192fabff0614d4f4841974ab3755f8661f37ac112a44ab2a8fa3eea41728aba461673b3fe1d2bd940d624691e61
|
data/.rubocop.yml
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
AllCops:
|
|
2
2
|
TargetRubyVersion: 3.2
|
|
3
|
+
NewCops: enable
|
|
3
4
|
|
|
4
5
|
Style/StringLiterals:
|
|
5
6
|
Enabled: true
|
|
@@ -11,3 +12,15 @@ Style/StringLiteralsInInterpolation:
|
|
|
11
12
|
|
|
12
13
|
Layout/LineLength:
|
|
13
14
|
Max: 120
|
|
15
|
+
|
|
16
|
+
Layout/LeadingCommentSpace:
|
|
17
|
+
Enabled: false
|
|
18
|
+
|
|
19
|
+
Metrics/ModuleLength:
|
|
20
|
+
Max: 250
|
|
21
|
+
|
|
22
|
+
Style/HashSyntax:
|
|
23
|
+
EnforcedShorthandSyntax: never
|
|
24
|
+
|
|
25
|
+
Style/TrailingCommaInHashLiteral:
|
|
26
|
+
EnforcedStyleForMultiline: comma
|
data/README.md
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
# Applin::Rails
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
https://www.applin.dev/
|
|
3
|
+
This is the source code for <https://rubygems.org/gems/applin-rails>.
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
Use this library to make a backend for your mobile app which uses
|
|
6
|
+
the Applin™ Server-Driven UI framework.
|
|
7
|
+
See <https://www.applin.dev/>
|
|
7
8
|
|
|
8
9
|
## Install
|
|
9
10
|
To add the gem to your Rails application:
|
|
@@ -11,11 +12,14 @@ To add the gem to your Rails application:
|
|
|
11
12
|
$ bundle add applin-rails
|
|
12
13
|
|
|
13
14
|
## Use
|
|
14
|
-
|
|
15
|
+
* Docs: <https://www.applin.dev/docs/backend-libraries.html>
|
|
16
|
+
* Example: <https://github.com/leonhard-llc/applin-rails-demo>
|
|
15
17
|
|
|
16
18
|
## Contributing
|
|
17
19
|
Bug reports and pull requests are welcome on GitHub at <https://github.com/leonhard-llc/applin-rails>.
|
|
18
20
|
|
|
21
|
+
When sending PRs, please email us a signed CLA using [cla-email-template.txt](cla-email-template.txt).
|
|
22
|
+
|
|
19
23
|
## Development
|
|
20
24
|
* Install dependencies: `bin/setup`
|
|
21
25
|
* `rake test`
|
|
@@ -23,6 +27,6 @@ Bug reports and pull requests are welcome on GitHub at <https://github.com/leonh
|
|
|
23
27
|
|
|
24
28
|
To release a new version:
|
|
25
29
|
1. Install the gem onto your local machine: `bundle exec rake install`
|
|
26
|
-
2. Test it with <https://github.com/leonhard-llc/applin-rails-
|
|
30
|
+
2. Test it with <https://github.com/leonhard-llc/applin-rails-demo>
|
|
27
31
|
1. Update the version number in `version.rb`
|
|
28
32
|
1. Run `bundle exec rake release`. This will create a git tag, make a `.gem` file, and push the file to <https://rubygems.org>.
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
To: michael@leonhardllc.com
|
|
2
|
+
Subject: signing cla
|
|
3
|
+
|
|
4
|
+
Hello Leonhard LLC,
|
|
5
|
+
I agree to the Software Grant and Corporate Contributor License
|
|
6
|
+
Agreement.
|
|
7
|
+
|
|
8
|
+
MY LEGAL NAME
|
|
9
|
+
MY@EMAIL.ADDRESS
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
Software Grant and Corporate Contributor License Agreement
|
|
14
|
+
|
|
15
|
+
In order to clarify the intellectual property license granted with
|
|
16
|
+
Contributions from any person or entity, Leonhard LLC must have a
|
|
17
|
+
Contributor License Agreement (CLA) on file that has been signed by
|
|
18
|
+
each Contributor, indicating agreement to the license terms
|
|
19
|
+
below. This license is for your protection as a Contributor as well as
|
|
20
|
+
the protection of Leonhard LLC and its users; it does not change your
|
|
21
|
+
rights to use your own Contributions for any other purpose.
|
|
22
|
+
|
|
23
|
+
This version of the Agreement allows an entity (the "Corporation") to
|
|
24
|
+
submit Contributions to Leonhard LLC, to authorize Contributions
|
|
25
|
+
submitted by its designated employees to Leonhard LLC, and to grant
|
|
26
|
+
copyright and patent licenses thereto.
|
|
27
|
+
|
|
28
|
+
You accept and agree to the following terms and conditions for Your
|
|
29
|
+
present and future Contributions submitted to Leonhard LLC. Except for
|
|
30
|
+
the license granted herein to Leonhard LLC and recipients of software
|
|
31
|
+
distributed by Leonhard LLC, You reserve all right, title, and
|
|
32
|
+
interest in and to Your Contributions.
|
|
33
|
+
|
|
34
|
+
1. Definitions.
|
|
35
|
+
|
|
36
|
+
"You" (or "Your") shall mean the copyright owner or legal entity
|
|
37
|
+
authorized by the copyright owner that is making this Agreement with
|
|
38
|
+
Leonhard LLC. For legal entities, the entity making a Contribution and
|
|
39
|
+
all other entities that control, are controlled by, or are under
|
|
40
|
+
common control with that entity are considered to be a single
|
|
41
|
+
Contributor. For the purposes of this definition, "control" means (i)
|
|
42
|
+
the power, direct or indirect, to cause the direction or management of
|
|
43
|
+
such entity, whether by contract or otherwise, or (ii) ownership of
|
|
44
|
+
fifty percent (50%) or more of the outstanding shares, or (iii)
|
|
45
|
+
beneficial ownership of such entity.
|
|
46
|
+
|
|
47
|
+
"Contribution" shall mean the code, documentation or any original work
|
|
48
|
+
of authorship, including any modifications or additions to an existing
|
|
49
|
+
work, that is intentionally submitted by You to Leonhard LLC for
|
|
50
|
+
inclusion in, or documentation of, any of the products owned or
|
|
51
|
+
managed by Leonhard LLC (the "Work"). For the purposes of this
|
|
52
|
+
definition, "submitted" means any form of electronic, verbal, or
|
|
53
|
+
written communication sent to Leonhard LLC or its representatives,
|
|
54
|
+
including but not limited to communication on electronic mailing
|
|
55
|
+
lists, source code control systems, and issue tracking systems that
|
|
56
|
+
are managed by, or on behalf of, Leonhard LLC for the purpose of
|
|
57
|
+
discussing and improving the Work, but excluding communication that is
|
|
58
|
+
conspicuously marked or otherwise designated in writing by You as "Not
|
|
59
|
+
a Contribution."
|
|
60
|
+
|
|
61
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
62
|
+
this Agreement, You hereby grant to Leonhard LLC and to recipients of
|
|
63
|
+
software distributed by Leonhard LLC a perpetual, worldwide,
|
|
64
|
+
non-exclusive, no-charge, royalty-free, irrevocable copyright license
|
|
65
|
+
to reproduce, prepare derivative works of, publicly display, publicly
|
|
66
|
+
perform, sublicense, and distribute Your Contributions and such
|
|
67
|
+
derivative works.
|
|
68
|
+
|
|
69
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
70
|
+
this Agreement, You hereby grant to Leonhard LLC and to recipients of
|
|
71
|
+
software distributed by Leonhard LLC a perpetual, worldwide,
|
|
72
|
+
non-exclusive, no-charge, royalty-free, irrevocable (except as stated
|
|
73
|
+
in this section) patent license to make, have made, use, offer to
|
|
74
|
+
sell, sell, import, and otherwise transfer the Work, where such
|
|
75
|
+
license applies only to those patent claims licensable by You that are
|
|
76
|
+
necessarily infringed by Your Contribution(s) alone or by combination
|
|
77
|
+
of Your Contribution(s) with the Work to which such Contribution(s)
|
|
78
|
+
was submitted. If any entity institutes patent litigation against You
|
|
79
|
+
or any other entity (including a cross-claim or counterclaim in a
|
|
80
|
+
lawsuit) alleging that your Contribution, or the Work to which you
|
|
81
|
+
have contributed, constitutes direct or contributory patent
|
|
82
|
+
infringement, then any patent licenses granted to that entity under
|
|
83
|
+
this Agreement for that Contribution or Work shall terminate as of the
|
|
84
|
+
date such litigation is filed.
|
|
85
|
+
|
|
86
|
+
4. You represent that You are legally entitled to grant the above
|
|
87
|
+
license. You represent further that each employee of the Corporation
|
|
88
|
+
designated by You is authorized to submit Contributions on behalf of
|
|
89
|
+
the Corporation.
|
|
90
|
+
|
|
91
|
+
5. You represent that each of Your Contributions is Your original
|
|
92
|
+
creation (see section 7 for submissions on behalf of others).
|
|
93
|
+
|
|
94
|
+
6. You are not expected to provide support for Your Contributions,
|
|
95
|
+
except to the extent You desire to provide support. You may provide
|
|
96
|
+
support for free, for a fee, or not at all. Unless required by
|
|
97
|
+
applicable law or agreed to in writing, You provide Your Contributions
|
|
98
|
+
on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
|
99
|
+
either express or implied, including, without limitation, any
|
|
100
|
+
warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY,
|
|
101
|
+
or FITNESS FOR A PARTICULAR PURPOSE.
|
|
102
|
+
|
|
103
|
+
7. Should You wish to submit work that is not Your original creation,
|
|
104
|
+
You may submit it to Leonhard LLC separately from any Contribution,
|
|
105
|
+
identifying the complete details of its source and of any license or
|
|
106
|
+
other restriction (including, but not limited to, related patents,
|
|
107
|
+
trademarks, and license agreements) of which you are personally aware,
|
|
108
|
+
and conspicuously marking the work as "Submitted on behalf of a
|
|
109
|
+
third-party: [named here]".
|
|
110
|
+
|
|
111
|
+
8. It is your responsibility to notify Leonhard LLC when any change is
|
|
112
|
+
required to the list of designated employees authorized to submit
|
|
113
|
+
Contributions on behalf of the Corporation, or to the Corporation's
|
|
114
|
+
Point of Contact with Leonhard LLC.
|
data/lib/applin/rails/version.rb
CHANGED
data/lib/applin/rails.rb
CHANGED
|
@@ -1,206 +1,18 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
-
require_relative "rails/version"
|
|
3
2
|
|
|
4
3
|
# https://guides.rubyonrails.org/action_controller_overview.html#restful-downloads
|
|
5
|
-
Mime::Type.register "application/vnd.applin_response", :
|
|
6
|
-
|
|
7
|
-
ActionController::Renderers.add :applin_response do |obj, options|
|
|
8
|
-
body = { page: obj }.to_json
|
|
9
|
-
options[:type] = Mime[:applin_response]
|
|
10
|
-
send_data body, options
|
|
11
|
-
end
|
|
4
|
+
Mime::Type.register "application/vnd.applin_response", :applin
|
|
12
5
|
|
|
13
6
|
module Applin
|
|
7
|
+
# Helper functions for creating Applin responses from controllers.
|
|
14
8
|
module Rails
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
ALIGN_START = "start"
|
|
18
|
-
ALLOW_ALL = "all"
|
|
19
|
-
ALLOW_ASCII = "ascii"
|
|
20
|
-
ALLOW_EMAIL = "email"
|
|
21
|
-
ALLOW_NUMBERS = "numbers"
|
|
22
|
-
ALLOW_TEL = "tel"
|
|
23
|
-
AUTO_CAPITALIZE_NAMES = "names"
|
|
24
|
-
AUTO_CAPITALIZE_SENTENCES = "sentences"
|
|
25
|
-
DISPOSITION_FIT = "fit"
|
|
26
|
-
DISPOSITION_STRETCH = "stretch"
|
|
27
|
-
DISPOSITION_COVER = "cover"
|
|
9
|
+
|
|
10
|
+
module_function
|
|
28
11
|
|
|
29
12
|
def send_page(page, options = {})
|
|
30
13
|
body = { page: page }.to_json
|
|
31
|
-
options[:type] = Mime[:
|
|
14
|
+
options[:type] = Mime[:applin]
|
|
32
15
|
send_data body, options
|
|
33
16
|
end
|
|
34
|
-
|
|
35
|
-
def back_button(actions:)
|
|
36
|
-
{ typ: :back_button, actions: actions }
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def button(text:, actions:)
|
|
40
|
-
{ typ: :button, text: text, actions: actions }
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def checkbox(text:, var_name:, actions: nil, initial_bool: nil, rpc: nil)
|
|
44
|
-
{
|
|
45
|
-
typ: :checkbox,
|
|
46
|
-
actions: actions,
|
|
47
|
-
initial_bool: initial_bool,
|
|
48
|
-
rpc: rpc,
|
|
49
|
-
text: text,
|
|
50
|
-
var_name: var_name,
|
|
51
|
-
}.reject { |_k, v| v.nil? }
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def column(widgets:, align: nil, spacing: nil)
|
|
55
|
-
{ typ: :column, align: align, spacing: spacing, widgets: widgets }.reject { |_k, v| v.nil? }
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def empty
|
|
59
|
-
{ typ: :empty }
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
# The client replaces `${INTERACTIVE_ERROR_DETAILS}` with the text of the last error.
|
|
63
|
-
def error_text(text)
|
|
64
|
-
{ typ: :error_text, text: text }
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def form(widgets:)
|
|
68
|
-
{ typ: :form, widgets: widgets }
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def form_button(text:, actions:, align: nil)
|
|
72
|
-
{ typ: :form_button, align: align, text: text, actions: actions }.reject { |_k, v| v.nil? }
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def form_section(widgets:, title: nil)
|
|
76
|
-
{ typ: :form_section, title: title, widgets: widgets }.reject { |_k, v| v.nil? }
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
# `row_groups` is a an array of arrays of widgets.
|
|
80
|
-
def grouped_row_table(row_groups:, spacing: nil)
|
|
81
|
-
{ typ: :grouped_row_table, spacing: spacing, row_groups: row_groups }.reject { |_k, v| v.nil? }
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
# Pass one of the DISPOSITION_* values for the `disposition` parameter.
|
|
85
|
-
def image(aspect_ratio:, url:, disposition: nil)
|
|
86
|
-
{ typ: :image, disposition: disposition, aspect_ratio: aspect_ratio, url: url }.reject { |_k, v| v.nil? }
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
def last_error_text
|
|
90
|
-
{ typ: :last_error_text }
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
def nav_button(text:, actions:, badge_text: nil, photo_url: nil, sub_text: nil)
|
|
94
|
-
{
|
|
95
|
-
typ: :nav_button,
|
|
96
|
-
badge_text: badge_text,
|
|
97
|
-
photo_url: photo_url,
|
|
98
|
-
sub_text: sub_text,
|
|
99
|
-
text: text,
|
|
100
|
-
actions: actions,
|
|
101
|
-
}.reject { |_k, v| v.nil? }
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
def scroll(&widget_block)
|
|
105
|
-
{ typ: :scroll, widget: widget_block.yield }
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
def text(text)
|
|
109
|
-
{ typ: :text, text: text }
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
# Pass one of the ALLOW_* values for `allow`.
|
|
113
|
-
# Pass one of the AUTO_CAPITALIZE_* values for `auto_capitalize`.
|
|
114
|
-
def textfield(
|
|
115
|
-
var_name:, allow: nil,
|
|
116
|
-
auto_capitalize: nil,
|
|
117
|
-
error: nil,
|
|
118
|
-
initial_string: nil,
|
|
119
|
-
label: nil,
|
|
120
|
-
max_chars: nil,
|
|
121
|
-
max_lines: nil,
|
|
122
|
-
min_chars: nil
|
|
123
|
-
)
|
|
124
|
-
{
|
|
125
|
-
typ: :textfield,
|
|
126
|
-
allow: allow,
|
|
127
|
-
auto_capitalize: auto_capitalize,
|
|
128
|
-
error: error,
|
|
129
|
-
initial_string: initial_string,
|
|
130
|
-
label: label,
|
|
131
|
-
max_chars: max_chars,
|
|
132
|
-
max_lines: max_lines,
|
|
133
|
-
min_chars: min_chars,
|
|
134
|
-
var_name: var_name,
|
|
135
|
-
}.reject { |_k, v| v.nil? }
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
def nav_page(title:, start: nil, end_: nil, ephemeral: nil, stream: nil, poll_seconds: nil, &widget_block)
|
|
139
|
-
{
|
|
140
|
-
typ: :nav_page,
|
|
141
|
-
start: start,
|
|
142
|
-
end: end_,
|
|
143
|
-
ephemeral: ephemeral,
|
|
144
|
-
title: title,
|
|
145
|
-
stream: stream,
|
|
146
|
-
poll_seconds: poll_seconds,
|
|
147
|
-
widget: widget_block.yield
|
|
148
|
-
}.reject { |_k, v| v.nil? }
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
def plain_page(title: nil, ephemeral: nil, stream: nil, poll_seconds: nil, &widget_block)
|
|
152
|
-
{
|
|
153
|
-
typ: :plain_page,
|
|
154
|
-
title: title,
|
|
155
|
-
ephemeral: ephemeral,
|
|
156
|
-
stream: stream,
|
|
157
|
-
poll_seconds: poll_seconds,
|
|
158
|
-
widget: widget_block.yield
|
|
159
|
-
}.reject { |_k, v| v.nil? }
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
def choose_photo(upload_url:)
|
|
163
|
-
"choose_photo:#{upload_url}"
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
def copy_to_clipboard(text)
|
|
167
|
-
"copy_to_clipboard:#{text}"
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
def launch_url(url)
|
|
171
|
-
"launch_url:#{url}"
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
def logout
|
|
175
|
-
"logout"
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
def nothing
|
|
179
|
-
"nothing"
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
def poll
|
|
183
|
-
"poll"
|
|
184
|
-
end
|
|
185
|
-
|
|
186
|
-
def pop
|
|
187
|
-
"pop"
|
|
188
|
-
end
|
|
189
|
-
|
|
190
|
-
def push(page_key)
|
|
191
|
-
"push:#{page_key}"
|
|
192
|
-
end
|
|
193
|
-
|
|
194
|
-
def replace_all(page_key)
|
|
195
|
-
"replace_all:#{page_key}"
|
|
196
|
-
end
|
|
197
|
-
|
|
198
|
-
def rpc(url)
|
|
199
|
-
"rpc:#{url}"
|
|
200
|
-
end
|
|
201
|
-
|
|
202
|
-
def take_photo(upload_url:)
|
|
203
|
-
"take_photo:#{upload_url}"
|
|
204
|
-
end
|
|
205
17
|
end
|
|
206
18
|
end
|
data/lib/applin.rb
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# rubocop:disable Metrics/MethodLength, Metrics/ParameterLists
|
|
4
|
+
|
|
5
|
+
# noinspection RubyTooManyMethodsInspection
|
|
6
|
+
module Applin
|
|
7
|
+
ALIGN_CENTER = "center"
|
|
8
|
+
ALIGN_END = "end"
|
|
9
|
+
ALIGN_START = "start"
|
|
10
|
+
ALLOW_ALL = "all"
|
|
11
|
+
ALLOW_ASCII = "ascii"
|
|
12
|
+
ALLOW_EMAIL = "email"
|
|
13
|
+
ALLOW_NUMBERS = "numbers"
|
|
14
|
+
ALLOW_TEL = "tel"
|
|
15
|
+
AUTO_CAPITALIZE_NAMES = "names"
|
|
16
|
+
AUTO_CAPITALIZE_SENTENCES = "sentences"
|
|
17
|
+
DISPOSITION_FIT = "fit"
|
|
18
|
+
DISPOSITION_STRETCH = "stretch"
|
|
19
|
+
DISPOSITION_COVER = "cover"
|
|
20
|
+
|
|
21
|
+
module_function
|
|
22
|
+
|
|
23
|
+
# Widgets ###################################################################
|
|
24
|
+
|
|
25
|
+
def back_button(actions:)
|
|
26
|
+
{ typ: :back_button, actions: actions }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def button(text:, actions:)
|
|
30
|
+
{ typ: :button, text: text, actions: actions }
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def checkbox(text:, var_name:, actions: nil, initial_bool: nil, rpc: nil)
|
|
34
|
+
{
|
|
35
|
+
typ: :checkbox,
|
|
36
|
+
actions: actions,
|
|
37
|
+
initial_bool: initial_bool,
|
|
38
|
+
rpc: rpc,
|
|
39
|
+
text: text,
|
|
40
|
+
var_name: var_name,
|
|
41
|
+
}.compact
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def column(widgets:, align: nil, spacing: nil)
|
|
45
|
+
{ typ: :column, align: align, spacing: spacing, widgets: widgets }.compact
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def empty
|
|
49
|
+
{ typ: :empty }
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# The client replaces `${INTERACTIVE_ERROR_DETAILS}` with the text of the last error.
|
|
53
|
+
def error_text(text)
|
|
54
|
+
{ typ: :error_text, text: text }
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def form(widgets:)
|
|
58
|
+
{ typ: :form, widgets: widgets }
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def form_button(text:, actions:, align: nil)
|
|
62
|
+
{ typ: :form_button, align: align, text: text, actions: actions }.compact
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def form_section(widgets:, title: nil)
|
|
66
|
+
{ typ: :form_section, title: title, widgets: widgets }.compact
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# `row_groups` is a an array of row groups.
|
|
70
|
+
# Each row group is an array of rows.
|
|
71
|
+
# Each row is an array of widgets.
|
|
72
|
+
def grouped_row_table(row_groups:, spacing: nil)
|
|
73
|
+
{ typ: :grouped_row_table, spacing: spacing, row_groups: row_groups }.compact
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Pass one of the DISPOSITION_* values for the `disposition` parameter.
|
|
77
|
+
def image(aspect_ratio:, url:, disposition: nil)
|
|
78
|
+
{ typ: :image, disposition: disposition, aspect_ratio: aspect_ratio, url: url }.compact
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def last_error_text
|
|
82
|
+
{ typ: :last_error_text }
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def nav_button(text:, actions:, badge_text: nil, photo_url: nil, sub_text: nil)
|
|
86
|
+
{
|
|
87
|
+
typ: :nav_button,
|
|
88
|
+
badge_text: badge_text,
|
|
89
|
+
photo_url: photo_url,
|
|
90
|
+
sub_text: sub_text,
|
|
91
|
+
text: text,
|
|
92
|
+
actions: actions,
|
|
93
|
+
}.compact
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def scroll(&widget_block)
|
|
97
|
+
{ typ: :scroll, widget: widget_block.yield }
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# `rows` is a an array of rows.
|
|
101
|
+
# Each row is an array of widgets.
|
|
102
|
+
def table(rows:, spacing: nil)
|
|
103
|
+
{ typ: :grouped_row_table, spacing: spacing, row_groups: [rows] }.compact
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def text(text)
|
|
107
|
+
{ typ: :text, text: text }
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Pass one of the ALLOW_* values for `allow`.
|
|
111
|
+
# Pass one of the AUTO_CAPITALIZE_* values for `auto_capitalize`.
|
|
112
|
+
def textfield(
|
|
113
|
+
var_name:,
|
|
114
|
+
allow: nil,
|
|
115
|
+
auto_capitalize: nil,
|
|
116
|
+
error: nil,
|
|
117
|
+
initial_string: nil,
|
|
118
|
+
label: nil,
|
|
119
|
+
max_chars: nil,
|
|
120
|
+
max_lines: nil,
|
|
121
|
+
min_chars: nil
|
|
122
|
+
)
|
|
123
|
+
{
|
|
124
|
+
typ: :textfield,
|
|
125
|
+
allow: allow,
|
|
126
|
+
auto_capitalize: auto_capitalize,
|
|
127
|
+
error: error,
|
|
128
|
+
initial_string: initial_string,
|
|
129
|
+
label: label,
|
|
130
|
+
max_chars: max_chars,
|
|
131
|
+
max_lines: max_lines,
|
|
132
|
+
min_chars: min_chars,
|
|
133
|
+
var_name: var_name,
|
|
134
|
+
}.compact
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Pages #####################################################################
|
|
138
|
+
|
|
139
|
+
def nav_page(
|
|
140
|
+
title:,
|
|
141
|
+
start: nil,
|
|
142
|
+
end_: nil,
|
|
143
|
+
ephemeral: nil,
|
|
144
|
+
stream: nil,
|
|
145
|
+
poll_seconds: nil,
|
|
146
|
+
&widget_block
|
|
147
|
+
)
|
|
148
|
+
{
|
|
149
|
+
typ: :nav_page,
|
|
150
|
+
start: start,
|
|
151
|
+
end: end_,
|
|
152
|
+
ephemeral: ephemeral,
|
|
153
|
+
title: title,
|
|
154
|
+
stream: stream,
|
|
155
|
+
poll_seconds: poll_seconds,
|
|
156
|
+
widget: widget_block.yield,
|
|
157
|
+
}.compact
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def plain_page(title: nil, ephemeral: nil, stream: nil, poll_seconds: nil, &widget_block)
|
|
161
|
+
{
|
|
162
|
+
typ: :plain_page,
|
|
163
|
+
title: title,
|
|
164
|
+
ephemeral: ephemeral,
|
|
165
|
+
stream: stream,
|
|
166
|
+
poll_seconds: poll_seconds,
|
|
167
|
+
widget: widget_block.yield,
|
|
168
|
+
}.compact
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# Actions ###################################################################
|
|
172
|
+
|
|
173
|
+
def choose_photo(upload_url:)
|
|
174
|
+
"choose_photo:#{upload_url}"
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def copy_to_clipboard(text)
|
|
178
|
+
"copy_to_clipboard:#{text}"
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def launch_url(url)
|
|
182
|
+
"launch_url:#{url}"
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def logout
|
|
186
|
+
"logout"
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def nothing
|
|
190
|
+
"nothing"
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def poll
|
|
194
|
+
"poll"
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def pop
|
|
198
|
+
"pop"
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def push(page_key)
|
|
202
|
+
"push:#{page_key}"
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def replace_all(page_key)
|
|
206
|
+
"replace_all:#{page_key}"
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def rpc(url)
|
|
210
|
+
"rpc:#{url}"
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def take_photo(upload_url:)
|
|
214
|
+
"take_photo:#{upload_url}"
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# rubocop:enable Metrics/MethodLength, Metrics/ParameterLists
|
|
218
|
+
end
|
data/sig/applin/rails.rbs
CHANGED
data/sig/applin.rbs
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# https://github.com/ruby/rbs#guides
|
|
2
|
+
|
|
3
|
+
module Applin
|
|
4
|
+
type alignment = String
|
|
5
|
+
|
|
6
|
+
ALIGN_CENTER: alignment
|
|
7
|
+
ALIGN_END: alignment
|
|
8
|
+
ALIGN_START: alignment
|
|
9
|
+
|
|
10
|
+
type allow = String
|
|
11
|
+
|
|
12
|
+
ALLOW_ALL: allow
|
|
13
|
+
ALLOW_ASCII: allow
|
|
14
|
+
ALLOW_EMAIL: allow
|
|
15
|
+
ALLOW_NUMBERS: allow
|
|
16
|
+
ALLOW_TEL: allow
|
|
17
|
+
|
|
18
|
+
type auto_capitalize = String
|
|
19
|
+
|
|
20
|
+
AUTO_CAPITALIZE_NAMES: auto_capitalize
|
|
21
|
+
AUTO_CAPITALIZE_SENTENCES: auto_capitalize
|
|
22
|
+
|
|
23
|
+
type disposition = String
|
|
24
|
+
|
|
25
|
+
DISPOSITION_COVER: disposition
|
|
26
|
+
DISPOSITION_FIT: disposition
|
|
27
|
+
DISPOSITION_STRETCH: disposition
|
|
28
|
+
VERSION: String
|
|
29
|
+
|
|
30
|
+
type action = String
|
|
31
|
+
type page = { title: String }
|
|
32
|
+
type widget = { typ: String }
|
|
33
|
+
|
|
34
|
+
def back_button: (actions: Array[action]) -> widget
|
|
35
|
+
|
|
36
|
+
def button: (text: String, actions: Array[action]) -> widget
|
|
37
|
+
|
|
38
|
+
def checkbox: (text: String, var_name: String, actions: Array[action]?, initial_bool: bool?, rpc: String?) -> widget
|
|
39
|
+
|
|
40
|
+
def choose_photo: (upload_url: String) -> action
|
|
41
|
+
|
|
42
|
+
def column: (widgets: Array[widget], align: alignment?, spacing: Numeric?) -> widget
|
|
43
|
+
|
|
44
|
+
def copy_to_clipboard: (String) -> action
|
|
45
|
+
|
|
46
|
+
def empty: -> widget
|
|
47
|
+
|
|
48
|
+
def error_text: (String) -> widget
|
|
49
|
+
|
|
50
|
+
def form: (widgets: Array[widget]) -> widget
|
|
51
|
+
|
|
52
|
+
def form_button: (text: String, actions: Array[action], align: alignment?) -> widget
|
|
53
|
+
|
|
54
|
+
def form_section: (widgets: Array[widget], title: String?) -> widget
|
|
55
|
+
|
|
56
|
+
def grouped_row_table: (row_groups: Array[Array[Array[widget]]], spacing: Numeric?) -> widget
|
|
57
|
+
|
|
58
|
+
def image: (aspect_ratio: Numeric, url: String, disposition: disposition?) -> widget
|
|
59
|
+
|
|
60
|
+
def last_error_text: -> widget
|
|
61
|
+
|
|
62
|
+
def launch_url: (String) -> action
|
|
63
|
+
|
|
64
|
+
def logout: -> action
|
|
65
|
+
|
|
66
|
+
def nav_button: (text: String, actions: Array[action], badge_text: String?, photo_url: String?, sub_text: String?) -> widget
|
|
67
|
+
|
|
68
|
+
def nav_page: (
|
|
69
|
+
title: String,
|
|
70
|
+
start: widget?,
|
|
71
|
+
end_: widget?,
|
|
72
|
+
ephemeral: bool?,
|
|
73
|
+
stream: bool?,
|
|
74
|
+
poll_seconds: Numeric?,
|
|
75
|
+
) { () -> widget } -> page
|
|
76
|
+
|
|
77
|
+
def nothing: -> action
|
|
78
|
+
|
|
79
|
+
def plain_page: (
|
|
80
|
+
title: String?,
|
|
81
|
+
ephemeral: bool?,
|
|
82
|
+
stream: bool?,
|
|
83
|
+
poll_seconds: Numeric?,
|
|
84
|
+
) { () -> widget } -> page
|
|
85
|
+
|
|
86
|
+
def poll: -> action
|
|
87
|
+
|
|
88
|
+
def pop: -> action
|
|
89
|
+
|
|
90
|
+
def push: (String) -> action
|
|
91
|
+
|
|
92
|
+
def replace_all: (String) -> action
|
|
93
|
+
|
|
94
|
+
def rpc: (String) -> action
|
|
95
|
+
|
|
96
|
+
def scroll: () { () -> widget } -> widget
|
|
97
|
+
|
|
98
|
+
def table: (rows: Array[Array[widget]], spacing: Numeric?) -> widget
|
|
99
|
+
|
|
100
|
+
def take_photo: (upload_url: String) -> action
|
|
101
|
+
|
|
102
|
+
def text: (String) -> widget
|
|
103
|
+
|
|
104
|
+
def textfield: (
|
|
105
|
+
var_name: String,
|
|
106
|
+
allow: allow?,
|
|
107
|
+
auto_capitalize: auto_capitalize?,
|
|
108
|
+
error: String?,
|
|
109
|
+
initial_string: String?,
|
|
110
|
+
label: String?,
|
|
111
|
+
max_chars: Numeric?,
|
|
112
|
+
max_lines: Numeric?,
|
|
113
|
+
min_chars: Numeric?
|
|
114
|
+
) -> widget
|
|
115
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: applin-rails
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Michael Leonhard
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2023-
|
|
11
|
+
date: 2023-10-26 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: Create mobile apps using only backend code. Applin™ is a Server-Driven
|
|
14
14
|
UI (SDUI) system.
|
|
@@ -23,8 +23,11 @@ files:
|
|
|
23
23
|
- LICENSE.md
|
|
24
24
|
- README.md
|
|
25
25
|
- Rakefile
|
|
26
|
+
- cla-email-template.txt
|
|
27
|
+
- lib/applin.rb
|
|
26
28
|
- lib/applin/rails.rb
|
|
27
29
|
- lib/applin/rails/version.rb
|
|
30
|
+
- sig/applin.rbs
|
|
28
31
|
- sig/applin/rails.rbs
|
|
29
32
|
homepage: https://www.applin.dev/
|
|
30
33
|
licenses:
|