suricate 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/lib/suricate/application.rb +90 -0
  3. data/lib/suricate/charts/chart.rb +15 -0
  4. data/lib/suricate/charts/chart_builder.rb +22 -0
  5. data/lib/suricate/charts/chart_serie.rb +19 -0
  6. data/lib/suricate/charts/chart_serie_builder.rb +29 -0
  7. data/lib/suricate/configuration/configuration.rb +13 -0
  8. data/lib/suricate/configuration/configuration_builder.rb +29 -0
  9. data/lib/suricate/configuration/widget_configuration.rb +24 -0
  10. data/lib/suricate/configuration/widget_configurations_builder.rb +64 -0
  11. data/lib/suricate/delegation_callback.rb +22 -0
  12. data/lib/suricate/generator/assets/javascript/api.js +53 -0
  13. data/lib/suricate/generator/assets/javascript/application.js +97 -0
  14. data/lib/suricate/generator/assets/javascript/chart-js-chart-factory.js +54 -0
  15. data/lib/suricate/generator/assets/javascript/suricate.js +4 -0
  16. data/lib/suricate/generator/assets/javascript/vendor/Chart.min.js +11 -0
  17. data/lib/suricate/generator/assets/javascript/vendor/bootstrap.min.js +7 -0
  18. data/lib/suricate/generator/assets/javascript/vendor/jquery.min.js +4 -0
  19. data/lib/suricate/generator/assets/javascript/widget-factory.js +43 -0
  20. data/lib/suricate/generator/assets/javascript/widget-updater.js +48 -0
  21. data/lib/suricate/generator/assets/javascript/widget-view.js +46 -0
  22. data/lib/suricate/generator/assets/javascript/widgets/counter-widget.js +23 -0
  23. data/lib/suricate/generator/assets/javascript/widgets/line-chart-widget.js +26 -0
  24. data/lib/suricate/generator/assets/javascript/widgets/widget.js +46 -0
  25. data/lib/suricate/generator/assets/javascript/widgets-container.js +22 -0
  26. data/lib/suricate/generator/assets/stylesheets/suricate.css +85 -0
  27. data/lib/suricate/generator/assets/stylesheets/vendor/bootstrap-theme.css.map +1 -0
  28. data/lib/suricate/generator/assets/stylesheets/vendor/bootstrap-theme.min.css +5 -0
  29. data/lib/suricate/generator/assets/stylesheets/vendor/bootstrap.css.map +1 -0
  30. data/lib/suricate/generator/assets/stylesheets/vendor/bootstrap.min.css +5 -0
  31. data/lib/suricate/output_driver.rb +28 -0
  32. data/lib/suricate/refinements/string.rb +27 -0
  33. data/lib/suricate/request_context.rb +14 -0
  34. data/lib/suricate/sinatra_output_driver.rb +14 -0
  35. data/lib/suricate/template/template.rb +11 -0
  36. data/lib/suricate/template/template_repository.rb +41 -0
  37. data/lib/suricate/version.rb +3 -0
  38. data/lib/suricate/widget_repository.rb +23 -0
  39. data/lib/suricate/widgets/counter_widget.rb +10 -0
  40. data/lib/suricate/widgets/line_chart_widget.rb +9 -0
  41. data/lib/suricate/widgets/responses/chart_widget_response.rb +17 -0
  42. data/lib/suricate/widgets/responses/counter_widget_response.rb +18 -0
  43. data/lib/suricate/widgets/widget.rb +31 -0
  44. data/lib/suricate.rb +50 -0
  45. metadata +200 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: fafd76c3fca39a449326894d87061f3fb75d3bd3
4
+ data.tar.gz: a0e8c87b6667fdda4c24ec5b7a5a8499ad0e7110
5
+ SHA512:
6
+ metadata.gz: f7bc99b933c0fd737d6f930b4340ca66679ca367f4b924c1b65f4bc0e9ae5e4c40d103dfe74a80bbc7c09c550af9225d3e46d58a5435a67c707df860251befb6
7
+ data.tar.gz: a81dac32f5283ff2e91ec188c250592db16a734f86f2eb2bf50b0c3ce639cdd7045fb6400a6044d7c36d312eda2b4a1a4b6c97d45ca443999b8463dcd155316b
@@ -0,0 +1,90 @@
1
+ require 'sinatra'
2
+ require 'json'
3
+
4
+ module Suricate
5
+ class Application < Sinatra::Base
6
+ extend Forwardable
7
+ def_delegators :@configuration, :widget_repository, :template_repository
8
+
9
+ def initialize(configuration)
10
+ super(nil)
11
+ # TODO : switch to Rack directly
12
+ # Good : hide Sinatra complexity from outside,
13
+ # the interface will be the same when switchting to Rack
14
+ # Bad : set class var from instance
15
+ self.class.set(:configuration, configuration)
16
+ @configuration = configuration
17
+ end
18
+
19
+ configure do
20
+ set :public_folder, Proc.new { configuration.public_directory }
21
+ set :views, Proc.new { configuration.templates_directory }
22
+ set :show_exceptions, :after_handler
23
+ end
24
+
25
+
26
+
27
+
28
+ #
29
+ # Errors
30
+ #
31
+
32
+ error WidgetRepository::WidgetNotFound do
33
+ output.api_error(404, env['sinatra.error'].message)
34
+ end
35
+
36
+
37
+
38
+
39
+ #
40
+ # API
41
+ #
42
+
43
+ # Get widgets' configuration
44
+ get('/api/widgets') do
45
+ configurations = widget_repository.configurations.map(&:to_h)
46
+ output.api_success(widgets: configurations)
47
+ end
48
+
49
+ # Get widget's data
50
+ get('/api/widgets/:id') do
51
+ widget = widget_repository.instantiate(params['id'], context)
52
+ widget.execute
53
+ end
54
+
55
+
56
+
57
+
58
+ #
59
+ # Pages
60
+ #
61
+
62
+ # Pages
63
+ get('/:page') do
64
+ render_page(params['page'])
65
+ end
66
+
67
+ # Default page
68
+ get('/') do
69
+ render_page(@configuration.default_page)
70
+ end
71
+
72
+
73
+
74
+
75
+ private
76
+ def context
77
+ RequestContext.new(request: request, session: session, output: output)
78
+ end
79
+
80
+ def output
81
+ @output ||= SinatraOutputDriver.new(self)
82
+ end
83
+
84
+ def render_page(page)
85
+ template = template_repository.find_page(page)
86
+ output.render(template.render)
87
+ end
88
+ end
89
+
90
+ end
@@ -0,0 +1,15 @@
1
+ module Suricate
2
+ class Chart
3
+ def initialize(labels, series)
4
+ @labels = labels
5
+ @series = series
6
+ end
7
+
8
+ def to_h
9
+ {
10
+ labels: @labels,
11
+ series: @series.map(&:to_h)
12
+ }
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,22 @@
1
+ module Suricate
2
+ class ChartBuilder
3
+ def initialize
4
+ @series = []
5
+ @labels = []
6
+ end
7
+
8
+ def serie
9
+ builder = ChartSerieBuilder.new
10
+ yield builder
11
+ @series << builder.serie
12
+ end
13
+
14
+ def labels(labels)
15
+ @labels = labels
16
+ end
17
+
18
+ def chart
19
+ Chart.new(@labels, @series)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,19 @@
1
+ module Suricate
2
+ class ChartSerie
3
+ attr_reader :name, :values, :color
4
+
5
+ def initialize(name, values, color)
6
+ @name = name
7
+ @values = values
8
+ @color = color
9
+ end
10
+
11
+ def to_h
12
+ {
13
+ name: @name,
14
+ values: @values,
15
+ color: @color
16
+ }
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,29 @@
1
+ module Suricate
2
+ class ChartSerieBuilder
3
+ def initialize
4
+ @values = []
5
+ end
6
+
7
+ def name(name)
8
+ @name = name
9
+ end
10
+
11
+ def color(color)
12
+ @color = color
13
+ end
14
+
15
+ # Add multiple values
16
+ def values(values)
17
+ @values.concat(values)
18
+ end
19
+
20
+ # Add one value
21
+ def value(value)
22
+ @values << value
23
+ end
24
+
25
+ def serie
26
+ ChartSerie.new(@name, @values, @color)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,13 @@
1
+ module Suricate
2
+ class Configuration
3
+ attr_reader :template_repository, :public_directory, :widget_repository,
4
+ :default_page
5
+
6
+ def initialize(options = {})
7
+ @template_repository = options[:template_repository]
8
+ @public_directory = options[:public_directory]
9
+ @widget_repository = options[:widget_repository]
10
+ @default_page = options[:default_page]
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,29 @@
1
+ module Suricate
2
+ class ConfigurationBuilder
3
+ attr_accessor :templates_directory, :public_directory, :default_page
4
+
5
+ def configuration
6
+ Configuration.new(template_repository: template_repository,
7
+ widget_repository: widget_repository,
8
+ default_page: @default_page,
9
+ public_directory: @public_directory)
10
+ end
11
+
12
+ def widgets
13
+ yield widget_configurations_builder
14
+ end
15
+
16
+ private
17
+ def template_repository
18
+ TemplateRepository.new(@templates_directory)
19
+ end
20
+
21
+ def widget_repository
22
+ WidgetRepository.new(widget_configurations_builder.configurations)
23
+ end
24
+
25
+ def widget_configurations_builder
26
+ @widgets_builder ||= WidgetConfigurationsBuilder.new(template_repository)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,24 @@
1
+ module Suricate
2
+ class WidgetConfiguration
3
+ attr_reader :id, :klass, :collector, :options
4
+
5
+ def initialize(id, klass, collector, options = {})
6
+ @id = id
7
+ @klass = klass
8
+ @collector = collector
9
+ @options = options
10
+ end
11
+
12
+ def instantiate(context)
13
+ @klass.new(id: id, context: context, collector: collector, options: options)
14
+ end
15
+
16
+ def to_h
17
+ {
18
+ id: @id,
19
+ type: @klass.type,
20
+ configuration: @options
21
+ }
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,64 @@
1
+ module Suricate
2
+ class WidgetConfigurationsBuilder
3
+ using Refinements::String
4
+ class IDAlreadyUsedError < StandardError; end
5
+ attr_reader :configurations
6
+
7
+ def initialize(template_repository)
8
+ @template_repository = template_repository
9
+ @configurations = []
10
+ end
11
+
12
+ def counter(id, collector, options = {})
13
+ register(id, CounterWidget, collector, options)
14
+ end
15
+
16
+ def line_chart(id, collector, options = {})
17
+ register(id, LineChartWidget, collector, options)
18
+ end
19
+
20
+ def register(id, klass, collector, options = {})
21
+ id = id.to_sym
22
+ if find_with_id(id)
23
+ raise IDAlreadyUsedError.new("id \"#{id}\" already taken")
24
+ else
25
+ configuration = build_configuration(id, klass, collector, options)
26
+ @configurations << configuration
27
+ end
28
+ end
29
+
30
+ private
31
+ def build_configuration(id, klass, collector, options)
32
+ build_options(id, klass.type, options)
33
+ WidgetConfiguration.new(id.to_sym, klass, collector, options)
34
+ end
35
+
36
+ def build_options(id, type, options)
37
+ options[:template] = find_widget_template(id, type, options[:template])
38
+ if options[:templates]
39
+ options[:templates].map! do |name|
40
+ @template_repository.find_widget(name)
41
+ end
42
+ end
43
+ end
44
+
45
+ def find_widget_template(id, type, wanted_template)
46
+ template = nil
47
+ default_template = type.underscore.sub(/_widget$/, '')
48
+ template_names = [wanted_template || id.to_s, default_template]
49
+
50
+ template_names.each do |name|
51
+ begin
52
+ template = @template_repository.find_widget(name) and break
53
+ rescue TemplateRepository::TemplateNotFound
54
+ end
55
+ end
56
+
57
+ template.render if template
58
+ end
59
+
60
+ def find_with_id(id)
61
+ @configurations.find { |conf| conf.id == id }
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,22 @@
1
+ module Suricate
2
+ class DelegationCallback
3
+ def initialize(*callbacks)
4
+ callbacks.each do |callback|
5
+ define_callback(callback)
6
+ end
7
+ end
8
+
9
+ def call(callback_name, *args)
10
+ callback = instance_variable_get(:"@#{callback_name}_callback")
11
+ callback.call(*args) if callback
12
+ end
13
+
14
+
15
+ private
16
+ def define_callback(callback)
17
+ define_singleton_method callback.to_sym do |&block|
18
+ instance_variable_set(:"@#{callback}_callback", block)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,53 @@
1
+ (function () {
2
+ "use strict";
3
+ window.Suricate = window.Suricate || {};
4
+
5
+ /*
6
+ * Public
7
+ */
8
+
9
+ Suricate.API = function(baseURL) {
10
+ this.baseURL = baseURL;
11
+ };
12
+
13
+ // Get widget configurations
14
+ Suricate.API.prototype.getWidgets = function(callback) {
15
+ this.sendRequest("GET", "/widgets", {}, function(data) {
16
+ callback(data.widgets);
17
+ });
18
+ };
19
+
20
+ // Get updated data for widget
21
+ Suricate.API.prototype.getWidgetData = function(widgetID, callback) {
22
+ var path = "/widgets/" + widgetID;
23
+ this.sendRequest("GET", path, {}, callback);
24
+ };
25
+
26
+
27
+ /*
28
+ * Private
29
+ */
30
+
31
+ // Send request to API
32
+ Suricate.API.prototype.sendRequest = function(method, path, params, callback) {
33
+ var self = this;
34
+ var url = this.baseURL + path;
35
+ $.ajax({
36
+ url: url,
37
+ method: method,
38
+ data: params,
39
+ success: function(data) {
40
+ self.handleResponse(url, data, callback);
41
+ }
42
+ });
43
+ };
44
+
45
+ Suricate.API.prototype.handleResponse = function(url, json, callback) {
46
+ if(json.status == 200) {
47
+ callback(json.data);
48
+ }
49
+ else {
50
+ console.error("Failed to load request", "url", url, "response", json);
51
+ }
52
+ };
53
+ }());
@@ -0,0 +1,97 @@
1
+ (function() {
2
+ "use strict";
3
+ window.Suricate = window.Suricate || {};
4
+
5
+ Suricate.Application = function(widgetsContainer, configuration) {
6
+ this.widgetsContainer = new Suricate.WidgetsContainer(widgetsContainer);
7
+ this.configuration = configuration;
8
+ this.chartFactory = configuration.chartFactory || new Suricate.ChartJSChartFactory();
9
+ this.initialized = false;
10
+ this.widgets = [];
11
+ this.updateInterval = undefined;
12
+ };
13
+
14
+
15
+
16
+ // Starts the application
17
+ Suricate.Application.prototype.start = function() {
18
+ var self = this;
19
+ this.init(function() {
20
+ self.startUpdates();
21
+ });
22
+ };
23
+
24
+ Suricate.Application.prototype.stop = function() {
25
+ this.stopUpdates();
26
+ };
27
+
28
+
29
+ // Creates and return an object
30
+ // to communicate with the API
31
+ Suricate.Application.prototype.createAPI = function() {
32
+ var baseURL = location.protocol + "//" + location.host + "/api";
33
+ return new Suricate.API(baseURL);
34
+ };
35
+
36
+ Suricate.Application.prototype.getWidgetsContainer = function() {
37
+ return this.widgetsContainer;
38
+ };
39
+
40
+ Suricate.Application.prototype.getChartFactory = function() {
41
+ return this.chartFactory;
42
+ };
43
+
44
+
45
+
46
+ /*
47
+ * Private
48
+ */
49
+
50
+ Suricate.Application.prototype.init = function(callback) {
51
+ if(!this.initialized) {
52
+ var self = this;
53
+ this.initWidgets(function() {
54
+ self.initialized = true;
55
+ callback();
56
+ });
57
+ }
58
+ else {
59
+ callback();
60
+ }
61
+ };
62
+
63
+ Suricate.Application.prototype.initWidgets = function(callback) {
64
+ var api = this.createAPI();
65
+ var self = this;
66
+ api.getWidgets(function(configurations) {
67
+ var factory = new Suricate.WidgetFactory(self, configurations);
68
+ self.widgets = factory.buildWidgets();
69
+ callback();
70
+ });
71
+ };
72
+
73
+ Suricate.Application.prototype.startUpdates = function() {
74
+ if(this.updateInterval === undefined) {
75
+ var self = this;
76
+ this.update();
77
+ this.updateInterval = window.setInterval(function() {
78
+ self.update();
79
+ }, 20000);
80
+ }
81
+ };
82
+
83
+ Suricate.Application.prototype.stopUpdates = function() {
84
+ if(this.updateInterval !== undefined) {
85
+ window.clearInterval(this.updateInterval);
86
+ this.updateInterval = undefined;
87
+ }
88
+ };
89
+
90
+ Suricate.Application.prototype.update = function() {
91
+ var now = new Date();
92
+ for (var widgetIndex = 0, l = this.widgets.length; widgetIndex < l; widgetIndex ++) {
93
+ var widget = this.widgets[widgetIndex];
94
+ widget.update(now);
95
+ }
96
+ };
97
+ }());
@@ -0,0 +1,54 @@
1
+ (function() {
2
+ "use strict";
3
+ window.Suricate = window.Suricate || {};
4
+
5
+ Suricate.ChartJSChartFactory = function() {
6
+
7
+ };
8
+
9
+ Suricate.ChartJSChartFactory.prototype.createLineChart = function(container, options) {
10
+ var chart = {};
11
+ var libraryObject;
12
+
13
+ var convertData = function(data) {
14
+ var datasets = [];
15
+ for (var index = 0, seriesCount = data.series.length; index < seriesCount; index++) {
16
+ var serie = data.series[index];
17
+ datasets.push({
18
+ label: serie.name,
19
+ strokeColor: serie.color,
20
+ fillColor: "rgba(0, 0, 0, 0)",
21
+ pointStrokeColor: serie.color,
22
+ pointColor: serie.color,
23
+ data: serie.values
24
+ });
25
+ }
26
+
27
+ return {
28
+ labels: data.labels,
29
+ datasets: datasets
30
+ };
31
+ };
32
+
33
+ var init = function(data, options) {
34
+ var ctx = container.find(".chart")[0].getContext("2d");
35
+ libraryObject = new Chart(ctx).Line(data, options);
36
+ var legend = libraryObject.generateLegend();
37
+ container.find(".legend").html(legend);
38
+ };
39
+
40
+ var data = {
41
+ labels: [],
42
+ datasets: [ { } ]
43
+ };
44
+ init(data, options);
45
+
46
+ chart.update = function(data) {
47
+ var chartJSData = convertData(data);
48
+ libraryObject.destroy();
49
+ init(chartJSData, options);
50
+ };
51
+
52
+ return chart;
53
+ };
54
+ }());
@@ -0,0 +1,4 @@
1
+ (function() {
2
+ "use strict";
3
+ window.Suricate = {};
4
+ }());