ruby-grafana-reporter 0.4.1 → 0.4.2
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/README.md +203 -185
- data/lib/VERSION.rb +2 -2
- data/lib/grafana/abstract_datasource.rb +25 -15
- data/lib/grafana/errors.rb +10 -2
- data/lib/grafana/grafana.rb +2 -0
- data/lib/grafana/grafana_property_datasource.rb +5 -0
- data/lib/grafana/graphite_datasource.rb +27 -5
- data/lib/grafana/influxdb_datasource.rb +70 -0
- data/lib/grafana/prometheus_datasource.rb +27 -5
- data/lib/grafana/sql_datasource.rb +9 -2
- data/lib/grafana/variable.rb +0 -1
- data/lib/grafana_reporter/abstract_query.rb +124 -23
- data/lib/grafana_reporter/abstract_report.rb +21 -2
- data/lib/grafana_reporter/alerts_table_query.rb +1 -6
- data/lib/grafana_reporter/annotations_table_query.rb +1 -6
- data/lib/grafana_reporter/application/webservice.rb +1 -1
- data/lib/grafana_reporter/asciidoctor/alerts_table_include_processor.rb +5 -4
- data/lib/grafana_reporter/asciidoctor/annotations_table_include_processor.rb +5 -4
- data/lib/grafana_reporter/asciidoctor/panel_image_block_macro.rb +1 -4
- data/lib/grafana_reporter/asciidoctor/panel_image_inline_macro.rb +1 -4
- data/lib/grafana_reporter/asciidoctor/panel_property_inline_macro.rb +1 -4
- data/lib/grafana_reporter/asciidoctor/panel_query_table_include_processor.rb +1 -5
- data/lib/grafana_reporter/asciidoctor/panel_query_value_inline_macro.rb +1 -4
- data/lib/grafana_reporter/asciidoctor/processor_mixin.rb +20 -35
- data/lib/grafana_reporter/asciidoctor/report.rb +2 -14
- data/lib/grafana_reporter/asciidoctor/sql_table_include_processor.rb +1 -3
- data/lib/grafana_reporter/asciidoctor/sql_value_inline_macro.rb +1 -3
- data/lib/grafana_reporter/demo_report_wizard.rb +5 -1
- data/lib/grafana_reporter/erb/report.rb +3 -16
- data/lib/grafana_reporter/erb/report_jail.rb +21 -0
- data/lib/grafana_reporter/errors.rb +14 -0
- data/lib/grafana_reporter/help.rb +2 -2
- data/lib/grafana_reporter/panel_image_query.rb +1 -5
- data/lib/grafana_reporter/query_value_query.rb +1 -19
- data/lib/ruby_grafana_reporter.rb +0 -12
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7ab1861d0ed6af7383a37bd357399451e38fb44d23489a52716660bae15a4f95
|
|
4
|
+
data.tar.gz: c744af8cd37f2fc469cef0d384d03e0610af5d38157a1367346f40986c29366c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d15b706ffae42fb3cdd39fd1e9ffc83823102566a6cda208e6196dbca9f637a740043b2a022e3529c26433c095bd99fd569722a73f61b35ad2808a2508ada7c2
|
|
7
|
+
data.tar.gz: 140c0502ef9340136a7ff42614353b024a5ac70d6af65a1c9bae30034783dbedc41c8b066f3a7bca1142c3c00f24f632fcae5d85c84318de67afd36dc5ef6370
|
data/README.md
CHANGED
|
@@ -1,185 +1,203 @@
|
|
|
1
|
-
[](https://github.com/divinity666/ruby-grafana-reporter/blob/master/LICENSE)
|
|
2
|
-
[](https://coveralls.io/github/divinity666/ruby-grafana-reporter?branch=master)
|
|
4
|
-
[](https://badge.fury.io/rb/ruby-grafana-reporter)
|
|
5
|
-
|
|
6
|
-
# Ruby Grafana Reporter
|
|
7
|
-
Reporting Service for Grafana
|
|
8
|
-
|
|
9
|
-
## Table of Contents
|
|
10
|
-
|
|
11
|
-
* [About the project](#about-the-project)
|
|
12
|
-
* [Features](#features)
|
|
13
|
-
* [
|
|
14
|
-
* [
|
|
15
|
-
* [
|
|
16
|
-
* [
|
|
17
|
-
* [
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
*
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
*
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
*
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
*
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
`http://<<your-server-url>>:<<your-webservice-port>>/render
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
1
|
+
[](https://github.com/divinity666/ruby-grafana-reporter/blob/master/LICENSE)
|
|
2
|
+
[](https://travis-ci.com/github/divinity666/ruby-grafana-reporter?branch=master)
|
|
3
|
+
[](https://coveralls.io/github/divinity666/ruby-grafana-reporter?branch=master)
|
|
4
|
+
[](https://badge.fury.io/rb/ruby-grafana-reporter)
|
|
5
|
+
|
|
6
|
+
# Ruby Grafana Reporter
|
|
7
|
+
Reporting Service for Grafana
|
|
8
|
+
|
|
9
|
+
## Table of Contents
|
|
10
|
+
|
|
11
|
+
* [About the project](#about-the-project)
|
|
12
|
+
* [Features](#features)
|
|
13
|
+
* [Supported datasources](#supported-datasources)
|
|
14
|
+
* [Quick Start](#quick-start)
|
|
15
|
+
* [Grafana integration](#grafana-integration)
|
|
16
|
+
* [Webservice overview](#webservice-overview)
|
|
17
|
+
* [Roadmap](#roadmap)
|
|
18
|
+
* [Donations](#donations)
|
|
19
|
+
|
|
20
|
+
## About the project
|
|
21
|
+
|
|
22
|
+
[Grafana](https://github.com/grafana/grafana) is a great tool for monitoring and
|
|
23
|
+
visualizing data from different sources. Anyway the free version is lacking a
|
|
24
|
+
professional reporting functionality. And this is, where the ruby grafana reporter
|
|
25
|
+
steps in.
|
|
26
|
+
|
|
27
|
+
The key functionality of the reporter is to capture data and images from grafana
|
|
28
|
+
dashboards and to use it in your custom reports to finally create reports in PDF,
|
|
29
|
+
HTML, or any other format.
|
|
30
|
+
|
|
31
|
+
By default (an extended version of) Asciidoctor is enabled as template language.
|
|
32
|
+
|
|
33
|
+
## Features
|
|
34
|
+
|
|
35
|
+
* Supports creation of reports for multiple [grafana](https://github.com/grafana/grafana)
|
|
36
|
+
dashboards (and also multiple grafana installations!) in one resulting report
|
|
37
|
+
* PDF (default), HTML and many other report formats are supported
|
|
38
|
+
* Easy-to-use configuration wizard, including fully automated functionality to create a
|
|
39
|
+
demo report for your dashboard
|
|
40
|
+
* Include dynamic content from grafana (find here a reference for all
|
|
41
|
+
[asciidcotor reporter calls](FUNCTION_CALLS.md)):
|
|
42
|
+
* panels as images
|
|
43
|
+
* tables based on grafana panel queries or custom database queries (no images!)
|
|
44
|
+
* single values to be integrated in text, based on grafana panel queries or custom
|
|
45
|
+
database queries
|
|
46
|
+
* Runs as
|
|
47
|
+
* webservice to be called directly from grafana
|
|
48
|
+
* standalone command line tool, e.g. to be automated with `cron` or `bash` scrips
|
|
49
|
+
* microservice from standard asciidoctor docker container without any dependencies
|
|
50
|
+
* Supports webhook callbacks on before, on cancel and on finishing a report (see
|
|
51
|
+
configuration file)
|
|
52
|
+
* Solid as a rock, also in case of template errors and whatever else may happen
|
|
53
|
+
* Full [API documentation](https://rubydoc.info/gems/ruby-grafana-reporter) available
|
|
54
|
+
|
|
55
|
+
## Supported datasources
|
|
56
|
+
|
|
57
|
+
Functionalities are provided as shown here:
|
|
58
|
+
|
|
59
|
+
Database | Image rendering | Raw queries | Composed queries
|
|
60
|
+
------------------------- | :-------------: | :-----------: | :------------:
|
|
61
|
+
all SQL based datasources | supported | supported | supported
|
|
62
|
+
Graphite | supported | supported | supported
|
|
63
|
+
InfluxDB | supported | supported | not (yet) supported
|
|
64
|
+
Prometheus | supported | supported | n/a in grafana
|
|
65
|
+
other datasources | supported | not supported | not supported
|
|
66
|
+
|
|
67
|
+
The characteristics of a raw query are, that the query is either specified manually in
|
|
68
|
+
the panel specification or in the calling template.
|
|
69
|
+
|
|
70
|
+
Composed queries are all kinds of query, where the grafana UI feature (aka visual editor
|
|
71
|
+
mode) for query specifications are used. In this case grafana is translating the UI query
|
|
72
|
+
specification to a raw query, which then in fact is sent to the database.
|
|
73
|
+
|
|
74
|
+
## Quick Start
|
|
75
|
+
|
|
76
|
+
You don't have a grafana setup runnning already? No worries, just configure
|
|
77
|
+
`https://play.grafana.org` in the configuration wizard and see the magic
|
|
78
|
+
happen!
|
|
79
|
+
|
|
80
|
+
If your grafana setup requires a login, you'll have to setup an api key for
|
|
81
|
+
the reporter. Please follow the steps
|
|
82
|
+
[described here](https://github.com/divinity666/ruby-grafana-reporter/issues/2#issuecomment-811836757)
|
|
83
|
+
first.
|
|
84
|
+
|
|
85
|
+
**Windows:**
|
|
86
|
+
|
|
87
|
+
* [Download latest Windows executable](https://github.com/divinity666/ruby-grafana-reporter/releases/latest)
|
|
88
|
+
* `ruby-grafana-reporter -w`
|
|
89
|
+
|
|
90
|
+
**Raspberry Pi:**
|
|
91
|
+
|
|
92
|
+
* `sudo apt-get install ruby`
|
|
93
|
+
* `gem install ruby-grafana-reporter`
|
|
94
|
+
* `ruby-grafana-reporter -w`
|
|
95
|
+
|
|
96
|
+
**Ruby environment:**
|
|
97
|
+
|
|
98
|
+
* `gem install ruby-grafana-reporter`
|
|
99
|
+
* `ruby-grafana-reporter -w`
|
|
100
|
+
|
|
101
|
+
**Docker environment** (advanced users):
|
|
102
|
+
|
|
103
|
+
* [Download latest single-rb file](https://github.com/divinity666/ruby-grafana-reporter/releases/latest)
|
|
104
|
+
to an empty folder
|
|
105
|
+
* create a configuration file by calling `ruby ruby-grafana-reporter -w` (if in doubt,
|
|
106
|
+
run the command within your docker container)
|
|
107
|
+
* create file `/<<path-to-single-rb-file-folder>>/startup.sh` with the following
|
|
108
|
+
content:
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
cd /documents
|
|
112
|
+
ruby bin/ruby-grafana-reporter
|
|
113
|
+
```
|
|
114
|
+
* add the startup script to your asciidoctor section in your docker-compose.yaml:
|
|
115
|
+
|
|
116
|
+
```
|
|
117
|
+
asciidoctor:
|
|
118
|
+
image: asciidoctor/docker-asciidoctor
|
|
119
|
+
container_name: asciidoctor
|
|
120
|
+
hostname: asciidoctor
|
|
121
|
+
volumes:
|
|
122
|
+
- /<<path-to-single-rb-file-folder>>:/documents
|
|
123
|
+
command:
|
|
124
|
+
sh /documents/startup.sh
|
|
125
|
+
restart: unless-stopped
|
|
126
|
+
```
|
|
127
|
+
* start/restart the asciidoctor docker container
|
|
128
|
+
|
|
129
|
+
## Grafana integration
|
|
130
|
+
|
|
131
|
+
For using the reporter directly from grafana, you need to simply add a link to your
|
|
132
|
+
grafana dashboard:
|
|
133
|
+
|
|
134
|
+
* Open the dashboard configuration
|
|
135
|
+
* Select `Links`
|
|
136
|
+
* Select `Add`
|
|
137
|
+
* Fill out as following:
|
|
138
|
+
* Type: `link`
|
|
139
|
+
* Url: `http://<<your-server-url>>:<<your-webservice-port>>/render?var-template=demo_report`
|
|
140
|
+
* Title: `Demo Report`
|
|
141
|
+
* Select `Time range`
|
|
142
|
+
* Select `Variable values`
|
|
143
|
+
* Select `Add`
|
|
144
|
+
|
|
145
|
+
Now go back to your dashboard and click the newly generated `Demo Report`
|
|
146
|
+
link on it. Now the renderer should start it's task and show you the expected
|
|
147
|
+
results.
|
|
148
|
+
|
|
149
|
+
Please note, that the reporter won't automatically refresh your screen to update
|
|
150
|
+
the progress. Simply hit `F5` to refresh your browser. After the report has been
|
|
151
|
+
successfully built, it will show the PDF after the next refresh automatically.
|
|
152
|
+
|
|
153
|
+
You want to select a template in grafana, which shall then be rendered?
|
|
154
|
+
Piece of cake: Just add a dashboard variable to your grafana dashboard named
|
|
155
|
+
`template` and let the user select or enter a template name. To make use of it,
|
|
156
|
+
you should change the link of the `Demo Report` link to
|
|
157
|
+
`http://<<your-server-url>>:<<your-webservice-port>>/render?`. On
|
|
158
|
+
hitting the new link in the dashboard, grafana will add the selected template as
|
|
159
|
+
a variable and forward it to the reporter.
|
|
160
|
+
|
|
161
|
+
## Webservice overview
|
|
162
|
+
|
|
163
|
+
Running the reporter as a webservice provides the following URLs
|
|
164
|
+
|
|
165
|
+
/overview - for all running or retained renderings
|
|
166
|
+
/render - for rendering a template, 'var-template' is the only mandatory GET parameter
|
|
167
|
+
/view_report - for viewing the status or receving the result of a specific rendering, is automatically called after a successfull /render call
|
|
168
|
+
/cancel_report - for cancelling the rendering of a specific report, normally not called manually, but on user interaction in the /view_report or /overview URL
|
|
169
|
+
|
|
170
|
+
The main endpoint to call for report generation is configured in the previous chapter [Grafana integration](#grafana-integration).
|
|
171
|
+
|
|
172
|
+
However, if you would like to see, currently running report generations and previously generated reports, you may want to call the endpoint `/overview`.
|
|
173
|
+
|
|
174
|
+
## Roadmap
|
|
175
|
+
|
|
176
|
+
This is just a collection of things, I am heading for in future, without a schedule.
|
|
177
|
+
|
|
178
|
+
* Support all grafana datasources
|
|
179
|
+
* Solve code TODOs
|
|
180
|
+
* Become [rubocop](https://rubocop.org/) ready
|
|
181
|
+
|
|
182
|
+
## Contributing
|
|
183
|
+
|
|
184
|
+
If you'd like to contribute, please fork the repository and use a feature
|
|
185
|
+
branch. Pull requests are warmly welcome.
|
|
186
|
+
|
|
187
|
+
## Licensing
|
|
188
|
+
|
|
189
|
+
The code in this project is licensed under MIT license.
|
|
190
|
+
|
|
191
|
+
## Acknowledgements
|
|
192
|
+
* [asciidoctor](https://github.com/asciidoctor/asciidoctor)
|
|
193
|
+
* [asciidoctor-pdf](https://github.com/asciidoctor/asciidoctor-pdf)
|
|
194
|
+
* [grafana](https://github.com/grafana/grafana)
|
|
195
|
+
|
|
196
|
+
Inspired by [Izak Marai's grafana reporter](https://github.com/IzakMarais/reporter)
|
|
197
|
+
|
|
198
|
+
## Donations
|
|
199
|
+
|
|
200
|
+
If this project saves you as much time as I hope it does, and if you'd like to
|
|
201
|
+
support my work, feel free donate. :)
|
|
202
|
+
|
|
203
|
+
[](https://www.paypal.com/donate?hosted_button_id=35LH6JNLPHPHQ)
|
data/lib/VERSION.rb
CHANGED
|
@@ -8,19 +8,18 @@ module Grafana
|
|
|
8
8
|
|
|
9
9
|
@@subclasses = []
|
|
10
10
|
|
|
11
|
-
# Registers the subclass as datasource
|
|
12
|
-
# model.
|
|
11
|
+
# Registers the subclass as datasource.
|
|
13
12
|
# @param subclass [Class] class inheriting from this abstract class
|
|
14
13
|
def self.inherited(subclass)
|
|
15
14
|
@@subclasses << subclass
|
|
16
15
|
end
|
|
17
16
|
|
|
18
17
|
# Overwrite this method, to specify if the current datasource implementation handles the given model.
|
|
19
|
-
# This method is called by {
|
|
18
|
+
# This method is called by {build_instance} to determine, if the current datasource implementation
|
|
20
19
|
# can handle the given grafana model. By default this method returns false.
|
|
21
20
|
# @param model [Hash] grafana specification of the datasource to check
|
|
22
21
|
# @return [Boolean] True if fits, false otherwise
|
|
23
|
-
def self.handles?(
|
|
22
|
+
def self.handles?(model)
|
|
24
23
|
false
|
|
25
24
|
end
|
|
26
25
|
|
|
@@ -78,12 +77,12 @@ module Grafana
|
|
|
78
77
|
# }
|
|
79
78
|
#
|
|
80
79
|
# @param query_description [Hash] query description, which will requested:
|
|
81
|
-
# @option [String] :from +from+ timestamp
|
|
82
|
-
# @option [String] :to +to+ timestamp
|
|
83
|
-
# @option [Integer] :timeout expected timeout for the request
|
|
84
|
-
# @option [WebRequest] :prepared_request prepared web request for relevant {Grafana} instance, if this is needed by datasource
|
|
85
|
-
# @option [String] :raw_query raw query, which shall be executed. May include variables, which will be replaced before execution
|
|
86
|
-
# @option [Hash<Variable>] :variables hash of variables, which can potentially be replaced in the given +:raw_query+
|
|
80
|
+
# @option query_description [String] :from +from+ timestamp
|
|
81
|
+
# @option query_description [String] :to +to+ timestamp
|
|
82
|
+
# @option query_description [Integer] :timeout expected timeout for the request
|
|
83
|
+
# @option query_description [WebRequest] :prepared_request prepared web request for relevant {Grafana} instance, if this is needed by datasource
|
|
84
|
+
# @option query_description [String] :raw_query raw query, which shall be executed. May include variables, which will be replaced before execution
|
|
85
|
+
# @option query_description [Hash<Variable>] :variables hash of variables, which can potentially be replaced in the given +:raw_query+
|
|
87
86
|
# @return [Hash] sql result formatted as stated above
|
|
88
87
|
def request(query_description)
|
|
89
88
|
raise NotImplementedError
|
|
@@ -101,6 +100,14 @@ module Grafana
|
|
|
101
100
|
raise NotImplementedError
|
|
102
101
|
end
|
|
103
102
|
|
|
103
|
+
# @abstract
|
|
104
|
+
#
|
|
105
|
+
# Overwrite in subclass, to specify the default variable format during replacement of variables.
|
|
106
|
+
# @return [String] default {Variable#value_formatted} format
|
|
107
|
+
def default_variable_format
|
|
108
|
+
raise NotImplementedError
|
|
109
|
+
end
|
|
110
|
+
|
|
104
111
|
private
|
|
105
112
|
|
|
106
113
|
# Replaces the grafana variables in the given string with their replacement value.
|
|
@@ -119,12 +126,15 @@ module Grafana
|
|
|
119
126
|
while repeat && (repeat_count < 3)
|
|
120
127
|
repeat = false
|
|
121
128
|
repeat_count += 1
|
|
122
|
-
variables.each do |
|
|
129
|
+
variables.each do |name, variable|
|
|
123
130
|
# only set ticks if value is string
|
|
124
|
-
|
|
125
|
-
res = res.gsub(/(?:\$\{#{
|
|
126
|
-
|
|
127
|
-
|
|
131
|
+
var_name = name.gsub(/^var-/, '')
|
|
132
|
+
res = res.gsub(/(?:\$\{#{var_name}(?::(?<format>\w+))?\}|\$#{var_name})/) do
|
|
133
|
+
format = default_variable_format
|
|
134
|
+
if $LAST_MATCH_INFO
|
|
135
|
+
format = $LAST_MATCH_INFO[:format] if $LAST_MATCH_INFO[:format]
|
|
136
|
+
end
|
|
137
|
+
variable.value_formatted(format)
|
|
128
138
|
end
|
|
129
139
|
end
|
|
130
140
|
repeat = true if res.include?('$')
|