statusboard 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.DS_Store +0 -0
- data/.gitignore +22 -0
- data/.ruby-version +1 -0
- data/ARCHITECTURE.md +14 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +296 -0
- data/Rakefile +2 -0
- data/examples/.gitkeep +0 -0
- data/examples/mountable.rb +74 -0
- data/examples/rendering_only.rb +21 -0
- data/examples/standalone.rb +59 -0
- data/lib/.DS_Store +0 -0
- data/lib/statusboard.rb +15 -0
- data/lib/statusboard/.DS_Store +0 -0
- data/lib/statusboard/dsl/base.rb +40 -0
- data/lib/statusboard/dsl/dsl.rb +262 -0
- data/lib/statusboard/errors.rb +2 -0
- data/lib/statusboard/main.rb +22 -0
- data/lib/statusboard/server.rb +29 -0
- data/lib/statusboard/version.rb +3 -0
- data/lib/statusboard/views/table/custom_cell.erb +1 -0
- data/lib/statusboard/views/table/image_cell.erb +6 -0
- data/lib/statusboard/views/table/percentage_cell.erb +7 -0
- data/lib/statusboard/views/table/row.erb +5 -0
- data/lib/statusboard/views/table/table.erb +7 -0
- data/lib/statusboard/views/table/text_cell.erb +5 -0
- data/lib/statusboard/widgets/.DS_Store +0 -0
- data/lib/statusboard/widgets/base.rb +37 -0
- data/lib/statusboard/widgets/diy.rb +17 -0
- data/lib/statusboard/widgets/graph.rb +22 -0
- data/lib/statusboard/widgets/table.rb +20 -0
- data/statusboard.gemspec +28 -0
- metadata +163 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1d8b58e432750151202b3c026d2dd4a4e631f37d
|
4
|
+
data.tar.gz: 511a95a6e5adcc91189b04d4173cd0c8245d8d60
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 97aa5838ef052af60bdafa2197b0e92d36163fd33b4c5170d2dc238a895889d9a9e69bbf2b3ba4e78533dad0e4cb2395f11fbb3cc4178c2e4a9013237f739a8b
|
7
|
+
data.tar.gz: 2ca1585052559e091ef5fba019b3006eb17a0866ce24d8ca212645dade9f41075ab2dc7aae1b35b71a92f060edc16aaab0ec7bb6496eab51f409f046aaa60c8b
|
data/.DS_Store
ADDED
Binary file
|
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.1.1
|
data/ARCHITECTURE.md
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
## Architecture
|
2
|
+
|
3
|
+
The gem differntiates between the application layer and the DSL.
|
4
|
+
|
5
|
+
### The DSL
|
6
|
+
The DSL is located in the `dsl` directory. All DSL-related classes normally end with `Description` (e.g. `GraphDescription`) and inherite from the class DSLBase.
|
7
|
+
|
8
|
+
As the "Description" suffix already states, the DSL objects can be seen as a description of what the application layer should do - similar to a config file in a "normal" application, but in a dynamic fashion. The task of the DSL part is to take the user input (which is achieved by being a DSL), sanitizing it where required and passing it with a useful structure to the application layer.
|
9
|
+
|
10
|
+
### The application layer
|
11
|
+
The application layer uses the description it received by evaluating the DSL and uses the information to produce the desired output (in this case graph widgets).
|
12
|
+
|
13
|
+
### Discussion
|
14
|
+
It should be discussed if the separation expalined above is useful or not.
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Julian Schuh
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,296 @@
|
|
1
|
+
# Statusboard
|
2
|
+
|
3
|
+
The statusboard gem provides a **simple, expressive DSL** which was purpose-built to feed your Panic-powered Status Board with data that matters to you. The DSL handles table, graph and DIY widgets in a way that renders messing around with raw data unnecessary.
|
4
|
+
|
5
|
+
The included server module makes serving the data to the app a simple and straight-forward process that doesn't require you to write any server-related code. The Rack-compliance of the server module makes the integration with existing systems a breeze.
|
6
|
+
|
7
|
+
[Visit the Panic website for more information about the Status Board app.](https://panic.com/statusboard/)
|
8
|
+
|
9
|
+
## Getting Started
|
10
|
+
|
11
|
+
### Installation
|
12
|
+
Install the gem by either running `gem install statusboard` or by adding the line `gem "statusboard"` to your Gemfile and running the `bundle` command.
|
13
|
+
|
14
|
+
### Your first Status Board data source:
|
15
|
+
|
16
|
+
Create a file called statusboard.rb with the following contents:
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
require "statusboard/main"
|
20
|
+
|
21
|
+
widget "yequalsx", :graph do
|
22
|
+
title "My first graph"
|
23
|
+
type :line
|
24
|
+
|
25
|
+
data do
|
26
|
+
data_sequence do
|
27
|
+
title "f(x) = x"
|
28
|
+
|
29
|
+
(0..15).each do |n|
|
30
|
+
datapoint n, n
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
```
|
36
|
+
|
37
|
+
and run `ruby statusboard.rb`. A webserver which serves the widget will automatically be started on port 8080. In your Status Board App, add a graph widget and set the URL to `your.ip:8080/widget/yequalsx`. A graph widget containing the plot of the mathematical function `f(x) = x` will be displayed.
|
38
|
+
|
39
|
+
For further and more complex examples **take a look at the `examples` directory**.
|
40
|
+
|
41
|
+
## DSL
|
42
|
+
The statusboard gem features a simple and expressive DSL which is used to configure and feed the widgets with data. Supported statements of the DSL are explained in the following paragraphs.
|
43
|
+
|
44
|
+
### widget
|
45
|
+
The **widget** statement is used to define a new widget with a specified _name_ and _type_. The widgets name is used as the identifier of the widget and hence has to be unique. A block containing further DSL statements which describe the widget and its contents must be specified.
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
widget name, type do
|
49
|
+
...
|
50
|
+
end
|
51
|
+
```
|
52
|
+
|
53
|
+
Supported types are `:table`, `:diy` and `:graph`. The specified type directly translates to the corresponding class, e.g. `:table` will use the class `Statusboard::TableWidget`.
|
54
|
+
|
55
|
+
Example:
|
56
|
+
```ruby
|
57
|
+
widget :sales, :graph do
|
58
|
+
...
|
59
|
+
end
|
60
|
+
```
|
61
|
+
The above code will define a graph-widget with the name `sales`. The widget will be available at the URL `http://your.ip:8080/widget/sales/`.
|
62
|
+
|
63
|
+
#### Advanced Features
|
64
|
+
- Custom widget types are supported: Create a subclass of `Statusboard::WidgetBase` in the `Statusboard` module with a name like `MycustomWidget` (replace `Mycustom`). Then use the corresponding identifier (e.g. `:mycustom`) with the widget statement.
|
65
|
+
- You can create a widget manually (by instanciating the widgets class) and pass the resulting object directly to the widget statement as the second parameter. In this case, the block must not be specified.
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
my_diy = Statusboard::DiyWidget.new do
|
69
|
+
...
|
70
|
+
end
|
71
|
+
|
72
|
+
widget :mycustom1, my_diy
|
73
|
+
```
|
74
|
+
|
75
|
+
### Table widget
|
76
|
+
A table widget provides one top-level statement: `data`, which accepts either a block or a proc. The specified block/proc should contain the code which is responsible to fetche the data which should be displayed. The block/proc will be executed every time the content of the widget is requested by the app.
|
77
|
+
Within the block/proc, the DSL can be used to specify the data:
|
78
|
+
|
79
|
+
The `row` statement creates a new row. A block must be specified in which the cells of the row are specified. The only statement that is accepted within `row` is the `cell` statement.
|
80
|
+
|
81
|
+
The `cell` statement creates a cell within a row. A `cell` can have different properties (represented by the corresponding DSL statements) as listed below:
|
82
|
+
|
83
|
+
| Statement | Description |
|
84
|
+
| ------------- | ------------- |
|
85
|
+
| type | Type of the cell. (Sell table below for supported types)|
|
86
|
+
| content | Main content of the cell. Depends on the cell type.|
|
87
|
+
| width | Width of the cell. Can be specified in px or percent. |
|
88
|
+
| colspan | Colspan of the cell |
|
89
|
+
| percentage | Percentage which should be displayed. Only used if cell type is `:percentage`|
|
90
|
+
| imageurl | URL of the image that should be displayed. Only used if cell type is `:image`|
|
91
|
+
| noresize | Indicates if the image should be resized or not. Only used if cell type is `:image`|
|
92
|
+
|
93
|
+
The following cell types are supported:
|
94
|
+
|
95
|
+
| Type | Description |
|
96
|
+
| ------------- | ------------- |
|
97
|
+
| `:text` | Displays the text specified as `content` |
|
98
|
+
| `:percentage` | Displays a percentage indicator. Percentage must be specified using the `percentage` statement |
|
99
|
+
| `:image` | Displays an image. URL must be specified using the `imageurl` statement. |
|
100
|
+
| `:cutsom` | Enables the use of custom cell. The cell (including all necessary HTML markup) must be specified using the `content` statement. |
|
101
|
+
|
102
|
+
Example:
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
data_proc = Proc.new do
|
106
|
+
row do
|
107
|
+
cell do
|
108
|
+
type :text
|
109
|
+
content "First row with 20%"
|
110
|
+
end
|
111
|
+
|
112
|
+
cell do
|
113
|
+
type :percentage
|
114
|
+
percentage 20
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
row do
|
119
|
+
cell do
|
120
|
+
type :text
|
121
|
+
content "Second row with 80%"
|
122
|
+
end
|
123
|
+
|
124
|
+
cell do
|
125
|
+
type :percentage
|
126
|
+
percentage 80
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
widget :testtable, :table do
|
132
|
+
data data_proc
|
133
|
+
end
|
134
|
+
```
|
135
|
+
|
136
|
+
### Graph Widget
|
137
|
+
|
138
|
+
A graph widget provides seven top-level statements:
|
139
|
+
|
140
|
+
| Statement | Description |
|
141
|
+
| ------------- | ------------- |
|
142
|
+
| `data` | A block or proc which handles fetching of the data. |
|
143
|
+
| `x_axis` | A block which can be used to configure the behavior of the X axis. |
|
144
|
+
| `y_axis` | A block which can be used to configure the behavior of the Y axis. |
|
145
|
+
| `refresh_interval` | Specifies how often the data should be refreshed by the app (in seconds). |
|
146
|
+
| `title` | Specified the title of the widget. |
|
147
|
+
| `type` | Specifies the type of the graph. Supported values: `:bar` and `:line` |
|
148
|
+
| `display_totals` | Specified wether or not the totals of all data sequences should be displayed. Can be called without parameter. |
|
149
|
+
|
150
|
+
|
151
|
+
#### The `data` statement
|
152
|
+
|
153
|
+
The `data` statement is used to feed the graph widget with data. It provides exactly one statement:
|
154
|
+
`data_sequence`.
|
155
|
+
The statement defines a new data sequence, which is a collection of data points that belong together. The data points of a sequence taken together yield to the corresponding line in the graph.The statement can be called multiple times if multiple data sequences should be specified.
|
156
|
+
|
157
|
+
The `data_sequence` again takes a block which is used to configure the data sequence and to specify the data which should be displayed:
|
158
|
+
|
159
|
+
| Statement | Description |
|
160
|
+
| ------------- | ------------- |
|
161
|
+
| `title` | Title describing the data sequence. E.g. "Sales per Day" |
|
162
|
+
| `color` | The color in which the line or bars should appear. |
|
163
|
+
| `datapoint` | Adds a data point to the current data sequence. The statement accespts *two* parameters: The **X** coordinate and the **Y** coordinate. The statement can be called multiple times in order to add multiple data points. Data points will displayed in the order they are added, _not_ sorted by the X coordinate. |
|
164
|
+
|
165
|
+
#### The `x_axis` statement
|
166
|
+
|
167
|
+
The following statement(s) are supported to configure the behavior of the **X** axis.
|
168
|
+
|
169
|
+
| Statement | Description |
|
170
|
+
| ------------- | ------------- |
|
171
|
+
| `show_every_label` | Forces every x datapoints to be displayed on the axis. Can be called without parameter. |
|
172
|
+
|
173
|
+
#### The `y_axis` statement
|
174
|
+
|
175
|
+
The following statement(s) are supported to configure the behavior of the **Y** axis.
|
176
|
+
|
177
|
+
| Statement | Description |
|
178
|
+
| ------------- | ------------- |
|
179
|
+
| `min_value` | Minimum value of the Y coordinate of every datapoint which should be displayed. |
|
180
|
+
| `max_value` | Maximum value of the Y coordinate of every datapoint which should be displayed. |
|
181
|
+
| `units_suffix` | Suffix which is appended to the Y axis labels. Can be used to add a unit to the raw data. |
|
182
|
+
| `units_prefix` | Prefix which is prepended to the Y axis labels. Can be used to add a unit to the raw data. |
|
183
|
+
| `scale_to` | Scales the Y coordinates by the specified value. |
|
184
|
+
| `hide_labels` | Specified if no lebsl should be displayed at all for the Y axis. Can be called without parameter. |
|
185
|
+
|
186
|
+
#### Example
|
187
|
+
|
188
|
+
```ruby
|
189
|
+
widget "yequalsx", :graph do
|
190
|
+
title "My first graph"
|
191
|
+
type :line
|
192
|
+
|
193
|
+
data do
|
194
|
+
data_sequence do
|
195
|
+
title "f(x) = x"
|
196
|
+
|
197
|
+
(0..15).each do |n|
|
198
|
+
datapoint n, n
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
```
|
204
|
+
|
205
|
+
### DIY Widget
|
206
|
+
|
207
|
+
The DIY widget allows to create completely custom-made, HTML-based widgets. As a further abstraction is not possible, the widgets offers only _one_ top-level statement: `content`. `content` awaits either a block, a proc or an arbitrary object which can be converted to a string.
|
208
|
+
|
209
|
+
Example:
|
210
|
+
|
211
|
+
```ruby
|
212
|
+
widget "custom", :diy do
|
213
|
+
content do
|
214
|
+
%w[this is a test].join(" ")
|
215
|
+
end
|
216
|
+
end
|
217
|
+
```
|
218
|
+
|
219
|
+
## Advanced Deployment
|
220
|
+
|
221
|
+
The gem can be deployed in _three_ different ways:
|
222
|
+
|
223
|
+
### **Standalone**
|
224
|
+
In this scenario, the gem is used to create a standalone server application whose only purpose is to serve data to the Status Board app. As this is the prevalent case, the gem was designed to support this scenario without having to write any code other than the code that acts as the data source.
|
225
|
+
|
226
|
+
If this scenario fits your needs best, just add the line
|
227
|
+
|
228
|
+
```ruby
|
229
|
+
require "statusboard/main"
|
230
|
+
```
|
231
|
+
|
232
|
+
to the top of your application file and define the widgets you want your Status Board to display using the DSL:
|
233
|
+
|
234
|
+
```ruby
|
235
|
+
widget "widget-name", :widget-type do
|
236
|
+
... use the DSL to describe the widget here
|
237
|
+
end
|
238
|
+
```
|
239
|
+
|
240
|
+
Run the file and a server is started automatically.
|
241
|
+
|
242
|
+
### As a module within an existing Rack-based app
|
243
|
+
In this scenario, the gem is used within an existing, Rack-based server application. The included Rack module is mounted in the application (e.g. using the routes.rb file of a rails app).
|
244
|
+
|
245
|
+
To create a server instance which can be used in a Rack-based environment, include the required files by adding the line
|
246
|
+
|
247
|
+
```ruby
|
248
|
+
require "statusboard"
|
249
|
+
```
|
250
|
+
to your application file.
|
251
|
+
|
252
|
+
Afterwards create the server instance and use its constructors block to describe the widgets which should be served:
|
253
|
+
|
254
|
+
```ruby
|
255
|
+
app = Statusboard::StatusboardServer.new do
|
256
|
+
widget ... do
|
257
|
+
...
|
258
|
+
end
|
259
|
+
end
|
260
|
+
```
|
261
|
+
|
262
|
+
Use `app` as a parameter to the mount call to integrate the Status Board serving with your existing app.
|
263
|
+
|
264
|
+
### Without a server
|
265
|
+
The gem can be used to describe a widget and construct the Status Board compatible ouput without using any of its server components. This allows for an easy integration into existing applications like non-Rack-based web servers or the generation of data which is used and/or served statically later on.
|
266
|
+
|
267
|
+
To use _only_ the data construction capabilities of the statusboard gem, add the following line to your application file:
|
268
|
+
|
269
|
+
```ruby
|
270
|
+
require "statusboard"
|
271
|
+
```
|
272
|
+
|
273
|
+
Afterwards you can instanciate the classes `Statusboard::DiyWidget`, `Statusboard::GraphWidget` or `Statusboard::TableWidget` by passing a block containing the DSL statements to the constructor. Call the `render` method on a newly created object to retrieve the Status Board compatible output:
|
274
|
+
|
275
|
+
```ruby
|
276
|
+
my_widget = Statusboard::DiyWidget.new do
|
277
|
+
content "My first widget with custom content!"
|
278
|
+
end
|
279
|
+
|
280
|
+
puts my_widget.render
|
281
|
+
```
|
282
|
+
|
283
|
+
## Todo
|
284
|
+
|
285
|
+
* Verify/discuss architecture of the gem
|
286
|
+
* Write meaningful tests
|
287
|
+
* Improve language of this document
|
288
|
+
|
289
|
+
## Contributing
|
290
|
+
|
291
|
+
1. Fork it ( https://github.com/julianschuh/statusboard/fork )
|
292
|
+
2. Read the ARCHITECTURE.md file
|
293
|
+
3. Create your feature branch (`git checkout -b my-new-feature`)
|
294
|
+
4. Commit your changes (`git commit -am 'Add some feature'`)
|
295
|
+
5. Push to the branch (`git push origin my-new-feature`)
|
296
|
+
6. Create a new Pull Request
|
data/Rakefile
ADDED
data/examples/.gitkeep
ADDED
File without changes
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require "statusboard"
|
2
|
+
|
3
|
+
# Required so we can run the statusboard server
|
4
|
+
require "rack/handler"
|
5
|
+
|
6
|
+
# Creates a Rackcompatible object which will serve the status board widgets when mounted or run.
|
7
|
+
mountable_module = Statusboard::StatusboardServer.new! do |variable|
|
8
|
+
|
9
|
+
# Specify a graph that plots the f(x)=x function
|
10
|
+
widget "yequalsx", :graph do
|
11
|
+
|
12
|
+
# Configure basic settings of the graph
|
13
|
+
title "My first graph"
|
14
|
+
type :line
|
15
|
+
|
16
|
+
# Specify the "data source" - in this case a block. (alternative: a proc)
|
17
|
+
data do
|
18
|
+
# One graph can have multiple data sequences (which translates to multiple lines/bar colors), we define one
|
19
|
+
data_sequence do
|
20
|
+
title "f(x) = x"
|
21
|
+
|
22
|
+
# The data sequence consists of 16 datapoints which represent the function f(x)=x from 0 to 15
|
23
|
+
(0..15).each do |n|
|
24
|
+
datapoint n, n
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Specify a table widget which contains the values of the function f(x) from 0 tp 15 (as plotted in the graph widget)
|
31
|
+
widget "yequalsxtable", :table do
|
32
|
+
|
33
|
+
# We specify the data as a block
|
34
|
+
data do
|
35
|
+
|
36
|
+
# Table header
|
37
|
+
row do
|
38
|
+
cell do
|
39
|
+
type :text
|
40
|
+
content "x"
|
41
|
+
end
|
42
|
+
cell do
|
43
|
+
type :text
|
44
|
+
content "f(x)"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Add a row for each value to the table
|
49
|
+
(0..15).each do |n|
|
50
|
+
row do
|
51
|
+
cell do
|
52
|
+
type :text
|
53
|
+
content n
|
54
|
+
end
|
55
|
+
cell do
|
56
|
+
type :text
|
57
|
+
content n
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
puts "Loaded widgets: "
|
66
|
+
mountable_module.server_description.widgets.keys.each do |widget_name|
|
67
|
+
puts widget_name
|
68
|
+
end
|
69
|
+
|
70
|
+
# Serve the widget using a Rack handler (could be mounted in an existing application, too).
|
71
|
+
# This is just for educational purposes; if you want to run the statusboard server standalone, you should
|
72
|
+
# require the file main.rb. When using main.rb, all initialization and server-related stuff is done
|
73
|
+
# automatically.
|
74
|
+
Rack::Handler.default.run(mountable_module)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require "statusboard"
|
2
|
+
|
3
|
+
# In this example, the Statusboard-compatible output will be generated without any server-related code
|
4
|
+
# being involved. Could be used to integrate the serving of Statusboard widgets into existing applications.
|
5
|
+
|
6
|
+
widget = Statusboard::GraphWidget.new do
|
7
|
+
title "My first graph"
|
8
|
+
type :line
|
9
|
+
|
10
|
+
data do
|
11
|
+
data_sequence do
|
12
|
+
title "f(x) = x"
|
13
|
+
|
14
|
+
(0..15).each do |n|
|
15
|
+
datapoint n, n
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
puts widget.render
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require "statusboard/main"
|
2
|
+
|
3
|
+
# Server listens on port 7777
|
4
|
+
server_settings :Port => 7777
|
5
|
+
|
6
|
+
# Specify a graph that plots the f(x)=x function
|
7
|
+
widget "yequalsx", :graph do
|
8
|
+
|
9
|
+
# Configure basic settings of the graph
|
10
|
+
title "My first graph"
|
11
|
+
type :line
|
12
|
+
|
13
|
+
# Specify the "data source" - in this case a block. (alternative: a proc)
|
14
|
+
data do
|
15
|
+
# One graph can have multiple data sequences (which translates to multiple lines/bar colors), we define one
|
16
|
+
data_sequence do
|
17
|
+
title "f(x) = x"
|
18
|
+
|
19
|
+
# The data sequence consists of 16 datapoints which represent the function f(x)=x from 0 to 15
|
20
|
+
(0..15).each do |n|
|
21
|
+
datapoint n, n
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Specify a table widget which contains the values of the function f(x) from 0 tp 15 (as plotted in the graph widget)
|
28
|
+
widget "yequalsxtable", :table do
|
29
|
+
|
30
|
+
# We specify the data as a block
|
31
|
+
data do
|
32
|
+
|
33
|
+
# Table header
|
34
|
+
row do
|
35
|
+
cell do
|
36
|
+
type :text
|
37
|
+
content "x"
|
38
|
+
end
|
39
|
+
cell do
|
40
|
+
type :text
|
41
|
+
content "f(x)"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Add a row for each value to the table
|
46
|
+
(0..15).each do |n|
|
47
|
+
row do
|
48
|
+
cell do
|
49
|
+
type :text
|
50
|
+
content n
|
51
|
+
end
|
52
|
+
cell do
|
53
|
+
type :text
|
54
|
+
content n
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/lib/.DS_Store
ADDED
Binary file
|
data/lib/statusboard.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require "statusboard/version"
|
2
|
+
|
3
|
+
require "statusboard/errors"
|
4
|
+
|
5
|
+
require "statusboard/dsl/dsl"
|
6
|
+
|
7
|
+
require "statusboard/widgets/graph"
|
8
|
+
require "statusboard/widgets/diy"
|
9
|
+
require "statusboard/widgets/table"
|
10
|
+
|
11
|
+
require "statusboard/server"
|
12
|
+
|
13
|
+
module Statusboard
|
14
|
+
VIEW_PATH = File.join(File.dirname(__FILE__), "statusboard", "views")
|
15
|
+
end
|
Binary file
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Statusboard
|
2
|
+
module DSL
|
3
|
+
class DSLBase
|
4
|
+
|
5
|
+
# Automatically creates DSL-like setters for the specified fields.
|
6
|
+
# Fields must be specified as symbols.
|
7
|
+
def self.setter(*method_names)
|
8
|
+
method_names.each do |name|
|
9
|
+
send :define_method, name do |data|
|
10
|
+
instance_variable_set "@#{name}".to_sym, data
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Automatically creates a DSL-like setter for a specified field. If
|
16
|
+
# the setter is called by the *user without an argument*, the specified
|
17
|
+
# default value will be used as the value.
|
18
|
+
#
|
19
|
+
# The method will _NOT_ use the specified value as a default value for
|
20
|
+
# the field. If a default value is needed, the field should be set in
|
21
|
+
# the constructor.
|
22
|
+
#
|
23
|
+
# ==== Attributes
|
24
|
+
#
|
25
|
+
# * +method_name+ - Name of the field for which a setter should be created
|
26
|
+
# * +default_value+ - Default value of the argument which is used if the method is called without an argument
|
27
|
+
def self.setter_with_default_value(method_name, default_value)
|
28
|
+
send :define_method, method_name do |data = default_value|
|
29
|
+
instance_variable_set "@#{method_name}".to_sym, data
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Default constructor. Executes the given block within its own context, so the block
|
34
|
+
# contents behave as a DSL.
|
35
|
+
def initialize(&block)
|
36
|
+
instance_eval &block
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,262 @@
|
|
1
|
+
require "statusboard/dsl/base"
|
2
|
+
|
3
|
+
module Statusboard
|
4
|
+
# Module whoch contains the definition of the DSL that is used to
|
5
|
+
# describe and configure the widgets and teir data(sources).
|
6
|
+
module DSL
|
7
|
+
class ServerDescription < DSLBase
|
8
|
+
|
9
|
+
attr_reader :widgets, :server_settings
|
10
|
+
|
11
|
+
def initialize(&block)
|
12
|
+
@widgets = {}
|
13
|
+
|
14
|
+
@server_settings = {
|
15
|
+
:Port => 8080,
|
16
|
+
:Host => "0.0.0.0"
|
17
|
+
}
|
18
|
+
|
19
|
+
super &block unless block.nil?
|
20
|
+
end
|
21
|
+
|
22
|
+
def server_settings(settings={})
|
23
|
+
@server_settings.merge!(settings)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Registers a new widget which will be served by the server.
|
27
|
+
#
|
28
|
+
# ==== Attributes
|
29
|
+
#
|
30
|
+
# * +name+ - Unique identifier of the widget. The widget will be accessible using the URL /widget/+name+
|
31
|
+
# * +type_or_widget+ - Either the type of the widget as a symbol (:table, :graph, :diy) or an already initialized widget object
|
32
|
+
# * +&block+ - If only the type of the widget was specified in the previous paremeter, the block must be specified and contain the DSL statements which descibe the widget
|
33
|
+
def widget(name, type_or_widget, &block)
|
34
|
+
raise ArgumentError, "Widget name " + name.to_s + " already taken" unless @widgets[name.to_sym].nil?
|
35
|
+
|
36
|
+
if type_or_widget.respond_to?(:render)
|
37
|
+
@widgets[name.to_sym] = type_or_widget
|
38
|
+
else
|
39
|
+
raise ArgumentError, "Widget " + name.to_s + " specified without block." if block.nil?
|
40
|
+
|
41
|
+
begin
|
42
|
+
klass = Statusboard.const_get(type_or_widget.to_s.capitalize + "Widget")
|
43
|
+
rescue NameError
|
44
|
+
raise ArgumentError, "Invalid widget type " + type_or_widget.to_s + " specified."
|
45
|
+
end
|
46
|
+
|
47
|
+
@widgets[name.to_sym] = klass.new(&block)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class GraphDescription < DSLBase
|
53
|
+
|
54
|
+
setter :refresh_interval, :title, :type
|
55
|
+
setter_with_default_value :display_totals, true
|
56
|
+
|
57
|
+
def data(proc = nil, &block)
|
58
|
+
@data = if proc.nil? then block else proc end
|
59
|
+
end
|
60
|
+
|
61
|
+
def x_axis(&block)
|
62
|
+
@x_axis = XAxis.new(&block)
|
63
|
+
end
|
64
|
+
|
65
|
+
def y_axis(&block)
|
66
|
+
@y_axis = YAxis.new(&block)
|
67
|
+
end
|
68
|
+
|
69
|
+
def construct
|
70
|
+
constructed = {
|
71
|
+
"graph" => {
|
72
|
+
"title" => @title,
|
73
|
+
"refreshEveryNSeconds" => @refresh_interval,
|
74
|
+
"totals" => @display_totals,
|
75
|
+
"type" => @type
|
76
|
+
}
|
77
|
+
}
|
78
|
+
|
79
|
+
begin
|
80
|
+
data = GraphData.new(&@data)
|
81
|
+
constructed["graph"]["datasequences"] = data.construct
|
82
|
+
rescue DataSourceError => e
|
83
|
+
constructed["graph"]["error"] = {
|
84
|
+
"message" => e.message,
|
85
|
+
"detail" => e.message
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
constructed["graph"]["xAxis"] = @x_axis.construct unless @x_axis.nil?
|
90
|
+
constructed["graph"]["yAxis"] = @y_axis.construct unless @y_axis.nil?
|
91
|
+
|
92
|
+
constructed
|
93
|
+
end
|
94
|
+
|
95
|
+
protected
|
96
|
+
|
97
|
+
class XAxis < DSLBase
|
98
|
+
setter_with_default_value :show_every_label, true
|
99
|
+
|
100
|
+
def construct
|
101
|
+
{
|
102
|
+
"showEveryLabel" => @show_every_label
|
103
|
+
}
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
class YAxis < DSLBase
|
108
|
+
|
109
|
+
setter :min_value, :max_value, :units_suffix, :units_prefix, :scale_to
|
110
|
+
setter_with_default_value :hide_labels, true
|
111
|
+
|
112
|
+
def construct
|
113
|
+
constructed = {
|
114
|
+
"scaleTo" => @scale_to,
|
115
|
+
"hide" => @hide_labels,
|
116
|
+
"units" => { }
|
117
|
+
}
|
118
|
+
|
119
|
+
constructed["minValue"] = @min_value unless @min_value.nil?
|
120
|
+
constructed["maxValue"] = @max_value unless @max_value.nil?
|
121
|
+
constructed["units"]["prefix"] = @units_prefix unless @units_prefix.nil?
|
122
|
+
constructed["units"]["suffix"] = @units_suffix unless @units_suffix.nil?
|
123
|
+
|
124
|
+
constructed
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
class GraphData < DSLBase
|
129
|
+
def initialize(&block)
|
130
|
+
@data_sequences = []
|
131
|
+
|
132
|
+
super &block
|
133
|
+
end
|
134
|
+
|
135
|
+
def data_sequence(title = nil, &block)
|
136
|
+
@data_sequences << DataSequence.new(title, &block)
|
137
|
+
end
|
138
|
+
|
139
|
+
def construct
|
140
|
+
@data_sequences.map(&:construct)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
class DataSequence < DSLBase
|
145
|
+
def initialize(title, &block)
|
146
|
+
@datapoints = []
|
147
|
+
@title = title
|
148
|
+
|
149
|
+
super &block
|
150
|
+
end
|
151
|
+
|
152
|
+
setter :title, :color
|
153
|
+
|
154
|
+
def datapoint(x, y)
|
155
|
+
@datapoints << {title: x.to_s, value: y.to_s}
|
156
|
+
end
|
157
|
+
|
158
|
+
def construct
|
159
|
+
constructed = {
|
160
|
+
"title" => @title,
|
161
|
+
"datapoints" => @datapoints
|
162
|
+
}
|
163
|
+
constructed["color"] = @color unless @color.nil?
|
164
|
+
|
165
|
+
constructed
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
class DiyDescription < DSLBase
|
171
|
+
def content(proc_or_content = nil, &block)
|
172
|
+
@content = if proc_or_content.nil? then block else proc_or_content end
|
173
|
+
end
|
174
|
+
|
175
|
+
def construct
|
176
|
+
content = if @content.respond_to?(:call) then @content.call() else @content end
|
177
|
+
|
178
|
+
{
|
179
|
+
content: content
|
180
|
+
}
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
class TableDescription < DSLBase
|
185
|
+
def data(proc = nil, &block)
|
186
|
+
@data = if proc.nil? then block else proc end
|
187
|
+
end
|
188
|
+
|
189
|
+
def construct
|
190
|
+
data = TableData.new(&@data).construct
|
191
|
+
|
192
|
+
{
|
193
|
+
data: data
|
194
|
+
}
|
195
|
+
end
|
196
|
+
|
197
|
+
protected
|
198
|
+
|
199
|
+
class TableData < DSLBase
|
200
|
+
def initialize(&block)
|
201
|
+
@rows = []
|
202
|
+
|
203
|
+
super &block
|
204
|
+
end
|
205
|
+
|
206
|
+
def row(&block)
|
207
|
+
@rows << TableRow.new(&block)
|
208
|
+
end
|
209
|
+
|
210
|
+
def construct
|
211
|
+
{
|
212
|
+
rows: @rows.map(&:construct)
|
213
|
+
}
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
class TableRow < DSLBase
|
218
|
+
def initialize(&block)
|
219
|
+
@cells = []
|
220
|
+
|
221
|
+
super &block
|
222
|
+
end
|
223
|
+
|
224
|
+
def cell(type = :text, &block)
|
225
|
+
@cells << TableCell.new(type, &block)
|
226
|
+
end
|
227
|
+
|
228
|
+
def construct
|
229
|
+
{
|
230
|
+
cells: @cells.map(&:construct)
|
231
|
+
}
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
class TableCell < DSLBase
|
236
|
+
setter :content, :colspan, :width, :percentage, :imageurl, :type
|
237
|
+
setter_with_default_value :noresize, true
|
238
|
+
|
239
|
+
def initialize(type, &block)
|
240
|
+
|
241
|
+
@type = :text
|
242
|
+
@type = type unless type.nil?
|
243
|
+
|
244
|
+
@noresize = false
|
245
|
+
|
246
|
+
super &block
|
247
|
+
end
|
248
|
+
|
249
|
+
def construct
|
250
|
+
{
|
251
|
+
content: @content,
|
252
|
+
type: @type,
|
253
|
+
width: @width,
|
254
|
+
percentage: @percentage,
|
255
|
+
imageurl: @imageurl,
|
256
|
+
noresize: @noresize
|
257
|
+
}
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "statusboard"
|
2
|
+
require "statusboard/server"
|
3
|
+
|
4
|
+
require "rack/handler"
|
5
|
+
require "rack-handlers"
|
6
|
+
|
7
|
+
app = Statusboard::StatusboardServer.new! # create a new, _unwrapped_ instance of the server class
|
8
|
+
|
9
|
+
# Make the top-level syntax work by delegating the right function calls to the right destination
|
10
|
+
Sinatra::Delegator.target = app.server_description # Why this? We want all top level function calls to be DSL calls -> So we have to call them in the actual DSL instance, and not the app class itself (which gets its settings from its DSL class instance)
|
11
|
+
Sinatra::Delegator.delegate :widget, :server_settings # Allowed calls
|
12
|
+
|
13
|
+
# include would include the module in Object
|
14
|
+
# extend only extends the main object
|
15
|
+
extend Sinatra::Delegator
|
16
|
+
|
17
|
+
class Rack::Builder
|
18
|
+
include Sinatra::Delegator
|
19
|
+
end
|
20
|
+
|
21
|
+
# Run the app _after_ the applications main file (where this file was included in) was executed successfully to allow for configuration
|
22
|
+
at_exit { Rack::Handler.default.run(app, app.server_description.server_settings) if $!.nil? }
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "sinatra/base"
|
2
|
+
|
3
|
+
module Statusboard
|
4
|
+
|
5
|
+
# Simple Sinatra-based server whose task it is to serve widgets to the app(s)
|
6
|
+
# using http. Widgets can be defined directly using the DSL or by passing already
|
7
|
+
# initialized Widget-objects. The widgets are identified using a unique name for
|
8
|
+
# each defined widget.
|
9
|
+
class StatusboardServer < Sinatra::Base
|
10
|
+
|
11
|
+
attr_reader :server_description
|
12
|
+
|
13
|
+
# Initializes a new instance of the server using the configuration specified via
|
14
|
+
# the DSL in the block. The server will be initialized without any widgets if no
|
15
|
+
# block is specified.
|
16
|
+
def initialize(*args, &block)
|
17
|
+
|
18
|
+
super(*args, &nil) # Dont pass the block to super as it would result in errors because the dsl methods aren't available if not instance_eval'd
|
19
|
+
|
20
|
+
@server_description = DSL::ServerDescription.new &block
|
21
|
+
end
|
22
|
+
|
23
|
+
get "/widget/:name/?" do |widget|
|
24
|
+
raise Sinatra::NotFound if @server_description.widgets[widget.to_sym].nil?
|
25
|
+
|
26
|
+
@server_description.widgets[widget.to_sym].render
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= content %>
|
Binary file
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require "erb"
|
2
|
+
require "tilt/erb"
|
3
|
+
|
4
|
+
module Statusboard
|
5
|
+
|
6
|
+
# (Abstract) class that represents a widget which can be displayed
|
7
|
+
# using the Status Board app.
|
8
|
+
# The class must be subclassed for each supported widget type.
|
9
|
+
class WidgetBase
|
10
|
+
|
11
|
+
# Each widget must be initialized using a DSL. When creating the
|
12
|
+
# widget, the block containing the DSL statements must be specified
|
13
|
+
# in the constructor.
|
14
|
+
def initialize(&block)
|
15
|
+
raise "Not implemented."
|
16
|
+
end
|
17
|
+
|
18
|
+
# Method that renders the specific widget into a (text-)format understandable
|
19
|
+
# by the Status Board app.
|
20
|
+
def render
|
21
|
+
raise "Not implemented."
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
# Renders a specified template with the specified local variables in the context
|
26
|
+
# of the object itself. The method will search for the template in a subdirectory
|
27
|
+
# of the gems VIEW_PATH. The subdirectory will be derived from the class name.
|
28
|
+
#
|
29
|
+
# Example:
|
30
|
+
# GraphWidget => views/graph/,
|
31
|
+
# TestWidget => views/test/
|
32
|
+
def render_template(template, locals = {})
|
33
|
+
widget_type = self.class.name.split('::').last.sub(/Widget$/, '').downcase
|
34
|
+
Tilt::ERBTemplate.new(File.join(Statusboard::VIEW_PATH, widget_type, template)).render(self, locals)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require "statusboard/widgets/base"
|
2
|
+
|
3
|
+
module Statusboard
|
4
|
+
|
5
|
+
# Represents do-it-yourself (DIY) widgets. The widget is configured and
|
6
|
+
# filled with data using a DSL which must be passed to the constructor.
|
7
|
+
class DiyWidget < WidgetBase
|
8
|
+
|
9
|
+
def initialize(&block)
|
10
|
+
@diy_description = DSL::DiyDescription.new(&block)
|
11
|
+
end
|
12
|
+
|
13
|
+
def render
|
14
|
+
@diy_description.construct[:content]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "statusboard/widgets/base"
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
|
5
|
+
module Statusboard
|
6
|
+
# Class which represents graph widgets for Status Board.
|
7
|
+
# The widget is configured and filled with data using a DSL
|
8
|
+
# whoch is passed to the constructor.
|
9
|
+
class GraphWidget < WidgetBase
|
10
|
+
|
11
|
+
# Initializes a new graph widget instance using the configuration
|
12
|
+
# and data source specified in the block. The block is excepted to
|
13
|
+
# use the DSL.
|
14
|
+
def initialize(&block)
|
15
|
+
@graph_description = DSL::GraphDescription.new(&block)
|
16
|
+
end
|
17
|
+
|
18
|
+
def render
|
19
|
+
@graph_description.construct.to_json
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require "statusboard/widgets/base"
|
2
|
+
|
3
|
+
module Statusboard
|
4
|
+
|
5
|
+
# Class which represents table widgets for Status Board.
|
6
|
+
# The widget is configured and filled with data using a DSL
|
7
|
+
# which is passed to the constructor.
|
8
|
+
class TableWidget < WidgetBase
|
9
|
+
|
10
|
+
def initialize(&block)
|
11
|
+
@table_description = DSL::TableDescription.new(&block)
|
12
|
+
end
|
13
|
+
|
14
|
+
def render
|
15
|
+
table_data = @table_description.construct
|
16
|
+
|
17
|
+
render_template("table.erb", table_data)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/statusboard.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'statusboard/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "statusboard"
|
8
|
+
spec.version = Statusboard::VERSION
|
9
|
+
spec.authors = ["Julian Schuh"]
|
10
|
+
spec.email = ["julez@julez.in"]
|
11
|
+
spec.summary = %q{Feed the Status Board App by Panic with custom data.}
|
12
|
+
spec.description = %q{Use a convenient and expressive DSL to feed the Status Board App by Panic with custom data. Benefit directly from rubys expressiveness without having to touch any server-related code.}
|
13
|
+
spec.homepage = "http://julez.io"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
|
24
|
+
spec.add_dependency "tilt", ">= 1.4.0" # Simple Template parsing
|
25
|
+
spec.add_dependency "rack-handlers", "~> 0.7" # Rack handler
|
26
|
+
spec.add_dependency "sinatra", "~> 1.4.5" # Server part is based on sinatra
|
27
|
+
spec.add_dependency "rack", "~> 1.5.2"
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,163 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: statusboard
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Julian Schuh
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-05-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.6'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: tilt
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 1.4.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.4.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rack-handlers
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.7'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.7'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: sinatra
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 1.4.5
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 1.4.5
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rack
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 1.5.2
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 1.5.2
|
97
|
+
description: Use a convenient and expressive DSL to feed the Status Board App by Panic
|
98
|
+
with custom data. Benefit directly from rubys expressiveness without having to touch
|
99
|
+
any server-related code.
|
100
|
+
email:
|
101
|
+
- julez@julez.in
|
102
|
+
executables: []
|
103
|
+
extensions: []
|
104
|
+
extra_rdoc_files: []
|
105
|
+
files:
|
106
|
+
- ".DS_Store"
|
107
|
+
- ".gitignore"
|
108
|
+
- ".ruby-version"
|
109
|
+
- ARCHITECTURE.md
|
110
|
+
- Gemfile
|
111
|
+
- LICENSE.txt
|
112
|
+
- README.md
|
113
|
+
- Rakefile
|
114
|
+
- examples/.gitkeep
|
115
|
+
- examples/mountable.rb
|
116
|
+
- examples/rendering_only.rb
|
117
|
+
- examples/standalone.rb
|
118
|
+
- lib/.DS_Store
|
119
|
+
- lib/statusboard.rb
|
120
|
+
- lib/statusboard/.DS_Store
|
121
|
+
- lib/statusboard/dsl/base.rb
|
122
|
+
- lib/statusboard/dsl/dsl.rb
|
123
|
+
- lib/statusboard/errors.rb
|
124
|
+
- lib/statusboard/main.rb
|
125
|
+
- lib/statusboard/server.rb
|
126
|
+
- lib/statusboard/version.rb
|
127
|
+
- lib/statusboard/views/table/custom_cell.erb
|
128
|
+
- lib/statusboard/views/table/image_cell.erb
|
129
|
+
- lib/statusboard/views/table/percentage_cell.erb
|
130
|
+
- lib/statusboard/views/table/row.erb
|
131
|
+
- lib/statusboard/views/table/table.erb
|
132
|
+
- lib/statusboard/views/table/text_cell.erb
|
133
|
+
- lib/statusboard/widgets/.DS_Store
|
134
|
+
- lib/statusboard/widgets/base.rb
|
135
|
+
- lib/statusboard/widgets/diy.rb
|
136
|
+
- lib/statusboard/widgets/graph.rb
|
137
|
+
- lib/statusboard/widgets/table.rb
|
138
|
+
- statusboard.gemspec
|
139
|
+
homepage: http://julez.io
|
140
|
+
licenses:
|
141
|
+
- MIT
|
142
|
+
metadata: {}
|
143
|
+
post_install_message:
|
144
|
+
rdoc_options: []
|
145
|
+
require_paths:
|
146
|
+
- lib
|
147
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
148
|
+
requirements:
|
149
|
+
- - ">="
|
150
|
+
- !ruby/object:Gem::Version
|
151
|
+
version: '0'
|
152
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
153
|
+
requirements:
|
154
|
+
- - ">="
|
155
|
+
- !ruby/object:Gem::Version
|
156
|
+
version: '0'
|
157
|
+
requirements: []
|
158
|
+
rubyforge_project:
|
159
|
+
rubygems_version: 2.2.2
|
160
|
+
signing_key:
|
161
|
+
specification_version: 4
|
162
|
+
summary: Feed the Status Board App by Panic with custom data.
|
163
|
+
test_files: []
|