omf_web 1.2.1 → 1.2.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.
@@ -41,12 +41,12 @@ module OMF::Web
41
41
 
42
42
  def load_environment(opts)
43
43
  unless cf = opts[:omf_config_file]
44
- puts "Missing config file"
44
+ fatal "Missing config file"
45
45
  abort
46
46
  end
47
47
 
48
48
  unless File.readable? cf
49
- puts "Can't read config file '#{cf}'"
49
+ fatal "Can't read config file '#{cf}'"
50
50
  abort
51
51
  end
52
52
 
@@ -75,18 +75,32 @@ module OMF::Web
75
75
  load_repository(repo)
76
76
  end
77
77
 
78
- unless wa = cfg[:widgets]
79
- puts "Can't find 'widgets' section in config file '#{cf}' - #{cfg.keys}"
78
+ widgets = cfg[:widgets] || []
79
+ if (tabs = cfg[:tabs])
80
+ tabs.each {|t| t[:top_level] = true}
81
+ widgets += tabs
82
+ end
83
+ if widgets.empty?
84
+ fatal "Can't find 'widgets' or 'tabs' section in config file '#{cf}' - #{cfg.keys}"
80
85
  abort
81
86
  end
82
- wa.each do |w|
83
- OMF::Web.register_widget w
87
+ widgets.each do |w|
88
+ register_widget w
89
+ end
90
+
91
+ # Any other file to load before opening shop
92
+ if init = cfg[:init]
93
+ unless init.is_a? Enumerable
94
+ init = [init]
95
+ end
96
+ init.each {|f| load_ruby_file(f) }
84
97
  end
98
+
85
99
  end
86
100
 
87
101
  def load_datasource(config)
88
102
  unless id = config[:id]
89
- puts "Missing id in datasource configuration"
103
+ fatal "Missing id in datasource configuration"
90
104
  abort
91
105
  end
92
106
  if config[:database]
@@ -95,6 +109,8 @@ module OMF::Web
95
109
  load_datasource_file(id, config)
96
110
  elsif config[:omsp]
97
111
  load_omsp_endpoint(id, config)
112
+ elsif config[:generator]
113
+ load_generator(id, config[:generator])
98
114
  else
99
115
  abort "Unknown datasource type - #{config}"
100
116
  end
@@ -102,13 +118,13 @@ module OMF::Web
102
118
 
103
119
  def load_database(id, config)
104
120
  unless db_cfg = config[:database]
105
- puts "Missing database configuration in datasource '#{config}'"
121
+ fatal "Missing database configuration in datasource '#{config}'"
106
122
  abort
107
123
  end
108
124
  db = get_database(db_cfg)
109
125
  if query_s = config[:query]
110
126
  unless schema = config[:schema]
111
- puts "Missing schema configuration in datasource '#{config}'"
127
+ fatal "Missing schema configuration in datasource '#{config}'"
112
128
  abort
113
129
  end
114
130
  require 'omf_oml/schema'
@@ -116,12 +132,12 @@ module OMF::Web
116
132
  table = db.create_table(id, config)
117
133
  else
118
134
  unless table_name = config.delete(:table)
119
- puts "Missing 'table' in datasource configuration '#{config}'"
135
+ fatal "Missing 'table' in datasource configuration '#{config}'"
120
136
  abort
121
137
  end
122
138
  config[:name] = id
123
139
  unless table = db.create_table(table_name, config)
124
- puts "Can't find table '#{table_name}' in database '#{db_cfg}'"
140
+ fatal "Can't find table '#{table_name}' in database '#{db_cfg}'"
125
141
  abort
126
142
  end
127
143
  end
@@ -136,23 +152,21 @@ module OMF::Web
136
152
  if db = @databases[config]
137
153
  return db
138
154
  end
139
- puts "Database '#{config}' not defined - (#{@databases.keys})"
140
- abort
141
- end
142
- unless id = config.delete(:id)
143
- puts "Missing id in database configuration"
155
+ fatal "Database '#{config}' not defined - (#{@databases.keys})"
144
156
  abort
145
157
  end
146
- if db = @databases[id.to_s] # already known
147
- return db
158
+ if id = config.delete(:id)
159
+ if db = @databases[id.to_s] # already known
160
+ return db
161
+ end
148
162
  end
149
163
 
150
164
  # unless id = config[:id]
151
- # puts "Database '#{config}' not defined - (#{@databases.keys})"
165
+ # fatal "Database '#{config}' not defined - (#{@databases.keys})"
152
166
  # abort
153
167
  # end
154
168
  unless url = config.delete(:url)
155
- puts "Missing URL for database '#{id}'"
169
+ fatal "Missing URL for database '#{id}'"
156
170
  abort
157
171
  end
158
172
  if url.start_with?('sqlite:') && ! url.start_with?('sqlite:/')
@@ -162,9 +176,11 @@ module OMF::Web
162
176
  config[:check_interval] ||= 3.0
163
177
  puts "URL: #{url} - #{config}"
164
178
  begin
165
- return @databases[id] = OMF::OML::OmlSqlSource.new(url, config)
179
+ db = OMF::OML::OmlSqlSource.new(url, config)
180
+ @databases[id] = db if id
181
+ return db
166
182
  rescue Exception => ex
167
- puts "Can't connect to database '#{id}' - #{ex}"
183
+ fatal "Can't connect to database '#{id}' - #{ex}"
168
184
  abort
169
185
  end
170
186
  end
@@ -175,24 +191,27 @@ module OMF::Web
175
191
  #
176
192
  def load_datasource_file(name, opts)
177
193
  unless file = opts[:file]
178
- puts "Data source file is not defined in '#{opts}'"
194
+ fatal "Data source file is not defined in '#{opts}'"
179
195
  abort
180
196
  end
181
197
  unless file.start_with? '/'
182
- file = File.join(@top_dir, file)
198
+ File.absolute_path(file, @cfg_dir)
183
199
  end
184
200
  unless File.readable? file
185
- puts "Can't read file '#{file}'"
201
+ fatal "Can't read file '#{file}'"
186
202
  abort
187
203
  end
188
- case content_type = opts[:content_type].to_s
204
+ unless content_type = opts[:content_type]
205
+ content_type = File.extname(file)[1 .. -1]
206
+ end
207
+ case content_type.to_s
189
208
  when 'json'
190
209
  ds = JSONDataSource.new(file)
191
210
  when 'csv'
192
211
  require 'omf_oml/csv_table'
193
212
  ds = OMF::OML::OmlCsvTable.create name, file, has_csv_header: true
194
213
  else
195
- puts "Unknown content type '#{content_type}'"
214
+ fatal "Unknown content type '#{content_type}'"
196
215
  abort
197
216
  end
198
217
  OMF::Web.register_datasource ds, name: name
@@ -201,21 +220,57 @@ module OMF::Web
201
220
  def load_omsp_endpoint(id, config)
202
221
  oconfig = config[:omsp]
203
222
  unless port = oconfig[:port]
204
- puts "Need port in OMSP definition '#{oconfig}' - datasource '#{id}'"
223
+ fatal "Need port in OMSP definition '#{oconfig}' - datasource '#{id}'"
205
224
  abort
206
225
  end
207
226
  ep = @omsp_endpoints[port] ||= OmspEndpointProxy.new(port)
208
227
  ep.add_datasource(id, config)
209
228
  end
210
229
 
230
+ def load_generator(id, config)
231
+ if file = config[:load]
232
+ load_ruby_file(file)
233
+ end
234
+ unless klass_name = config[:class]
235
+ fatal "Missing 'class' options for generator '#{id}'"
236
+ abort
237
+ end
238
+ klass = nil
239
+ begin
240
+ klass = Kernel.const_get(klass_name)
241
+ rescue
242
+ fatal "Can't find class '#{klass_name}' referenced in generator '#{id}'"
243
+ abort
244
+ end
245
+ opts = config[:opts] || {}
246
+ debug "Creating new generator '#{id}' from '#{klass_name}' with '#{opts}'"
247
+ unless klass.respond_to? :create_data_source
248
+ fatal "Class '#{klass_name}' doesn't have a 'create_data_source' class method."
249
+ abort
250
+ end
251
+ klass.create_data_source(id, opts)
252
+ end
253
+
254
+ def load_ruby_file(file)
255
+ unless file.start_with? '/'
256
+ file = File.absolute_path(file, @cfg_dir)
257
+ end
258
+ unless File.readable? file
259
+ fatal "Can't read file '#{file}'"
260
+ abort
261
+ end
262
+ debug "Loading #{file}"
263
+ load(file)
264
+ end
265
+
211
266
 
212
267
  def load_repository(config)
213
268
  unless id = config[:id]
214
- puts "Missing id in respository configuration"
269
+ fatal "Missing id in respository configuration"
215
270
  abort
216
271
  end
217
272
  unless type = config[:type]
218
- puts "Missing 'type' in respository configuration '#{id}'"
273
+ fatal "Missing 'type' in respository configuration '#{id}'"
219
274
  abort
220
275
  end
221
276
 
@@ -223,20 +278,31 @@ module OMF::Web
223
278
  case type
224
279
  when 'file'
225
280
  unless top_dir = config[:top_dir]
226
- puts "Missing 'top_dir' in respository configuration '#{id}'"
281
+ fatal "Missing 'top_dir' in respository configuration '#{id}'"
227
282
  abort
228
283
  end
229
284
  unless top_dir.start_with? '/'
230
- top_dir = File.join(@top_dir, top_dir)
285
+ top_dir = File.join(@cfg_dir, top_dir)
231
286
  end
287
+ #puts "TOP>>> #{File.absolute_path top_dir}"
232
288
  OMF::Web::ContentRepository.register_repo(id, type: :file, top_dir: top_dir)
233
289
  else
234
- puts "Unknown repository type '#{type}'. Only supporting 'file'."
290
+ fatal "Unknown repository type '#{type}'. Only supporting 'file'."
235
291
  abort
236
292
  end
237
293
 
238
294
  end
239
295
 
296
+ def register_widget(w)
297
+ unless w[:id]
298
+ require 'digest/md5'
299
+ w[:id] = Digest::MD5.hexdigest(w[:name] || "tab#{rand(10000)}")[0, 8]
300
+ end
301
+ w[:top_level] = true
302
+ w[:type] ||= 'layout/one_column'
303
+ OMF::Web.register_widget w
304
+ end
305
+
240
306
  # Recusively Symbolize keys of hash
241
307
  #
242
308
  def _rec_sym_keys(hash)
@@ -330,4 +396,4 @@ module OMF::Web
330
396
  end # class OmspEndpointProxy
331
397
 
332
398
  end # class
333
- end # module
399
+ end # module
@@ -1,7 +1,7 @@
1
1
 
2
2
  module OMF
3
3
  module Web
4
- VERSION = '1.2.1'
4
+ VERSION = '1.2.2'
5
5
  # Used for finding the example directory
6
6
  TOP_DIR = File.dirname(File.dirname(File.dirname(__FILE__)))
7
7
  end
data/omf_web.gemspec CHANGED
@@ -34,6 +34,7 @@ Gem::Specification.new do |s|
34
34
  s.add_runtime_dependency "websocket-rack", "~> 0.4.0"
35
35
  s.add_runtime_dependency "rack-accept", "~> 0.4.0"
36
36
  s.add_runtime_dependency "i18n"
37
+ s.add_runtime_dependency "rake"
37
38
 
38
39
  # Do we need the next two dependencies?
39
40
  #s.add_runtime_dependency "sqlite3", "~> 1.3.6"
@@ -77,6 +77,13 @@ define(["graph/abstract_widget"], function (abstract_widget) {
77
77
  this.update();
78
78
  },
79
79
 
80
+ configure_base_layer: function(vis) {
81
+ this.base_layer = vis.append("svg:g");
82
+ if (this.base_css_class) {
83
+ this.base_layer.attr("class", this.base_css_class);
84
+ }
85
+ },
86
+
80
87
  _resize_base_el: function(w, h) {
81
88
  // Do not add margins to the base_el, but to the inside of the SVG panes
82
89
  this.w = w;
@@ -290,4 +297,4 @@ define(["graph/abstract_widget"], function (abstract_widget) {
290
297
  });
291
298
 
292
299
  return abstract_chart;
293
- });
300
+ });
@@ -0,0 +1,82 @@
1
+
2
+ define(["graph/abstract_chart"], function(abstract_chart) {
3
+
4
+ var graph = abstract_chart.extend({
5
+ // MAKE SURE THIS IS DEFINED IN SUB CLASS
6
+ data_source_names: ['change', 'me'],
7
+
8
+ initialize: function(opts) {
9
+ graph.__super__.initialize.call(this, opts);
10
+ },
11
+
12
+ // Find the appropriate data source and bind to it
13
+ //
14
+ init_data_source: function() {
15
+ var self = this;
16
+ var o = self.opts;
17
+ var sources = o.data_sources;
18
+ var ds_names = self.data_source_names;
19
+
20
+ if (! (sources instanceof Array)) {
21
+ throw "Expected an array";
22
+ }
23
+ if (sources.length != ds_names.length) {
24
+ throw "Expected '" + ds_names.length + "' data source, but only found '" + sources.length + "'.";
25
+ }
26
+
27
+ var dsh = self.data_source = {};
28
+ _.map(sources, function(s) {
29
+ dsh[s.name] = self.init_single_data_source(s);
30
+ });
31
+ _.each(ds_names, function(ds_name) {
32
+ if (dsh[ds_name] == undefined) {
33
+ throw "Missing data source '" + ds_name + "'. Check for spelling of name.";
34
+ }
35
+ });
36
+ },
37
+
38
+ process_schema: function() {
39
+ var self = this;
40
+ var ds_names = self.data_source_names;
41
+
42
+ var schemas = self.schema = {};
43
+ _.each(ds_names, function(ds_name) {
44
+ schemas[ds_name] = self.process_single_schema(self.data_source[ds_name]);
45
+ });
46
+
47
+ var om = self.opts.mapping;
48
+ if (om == undefined) {
49
+ throw "Missing mapping instructions in 'options'.";
50
+ }
51
+ self.mapping = {};
52
+ _.each(ds_names, function(ds_name) {
53
+ var mapping = om[ds_name];
54
+ if (mapping == undefined) {
55
+ throw "Missing mapping instructions in 'options' for '" + ds_name + "'.";
56
+ }
57
+ self.mapping[ds_name] = self.process_single_mapping(ds_name, mapping, self.decl_properties[ds_name]);
58
+ });
59
+ },
60
+
61
+ /*
62
+ * Return schema for +stream+.
63
+ */
64
+ schema_for_stream: function(stream) {
65
+ var schema = this.schema[stream];
66
+ return schema;
67
+ },
68
+
69
+ update: function() {
70
+ var data = {};
71
+ var self = this;
72
+
73
+ _.each(self.data_source_names, function(ds_name) {
74
+ data[ds_name] = self.data_source[ds_name].rows();
75
+ }, self);
76
+ self.redraw(data);
77
+ },
78
+
79
+ }); // end of graph
80
+
81
+ return graph;
82
+ });
@@ -31,7 +31,7 @@ define(['omf/data_source_repo', 'vendor/d3/d3'], function(ds_repo) {
31
31
  x: 0,
32
32
  y: 0
33
33
  },
34
- }
34
+ };
35
35
  },
36
36
 
37
37
  //base_css_class: 'oml-chart',
@@ -93,6 +93,8 @@ define(['omf/data_source_repo', 'vendor/d3/d3'], function(ds_repo) {
93
93
  }
94
94
  this._resize_base_el(w,h);
95
95
 
96
+ OHUB.trigger(o.id + '.resize', {width: w, height: h});
97
+
96
98
  return this;
97
99
  },
98
100
 
@@ -120,10 +122,10 @@ define(['omf/data_source_repo', 'vendor/d3/d3'], function(ds_repo) {
120
122
  var self = this;
121
123
 
122
124
  if (! (sources instanceof Array)) {
123
- throw "Expected an array"
125
+ throw "Expected an array";
124
126
  }
125
127
  if (sources.length != 1) {
126
- throw "Can only process a SINGLE source"
128
+ throw "Can only process a SINGLE source";
127
129
  }
128
130
  this.data_source = this.init_single_data_source(sources[0]);
129
131
  },
@@ -136,7 +138,7 @@ define(['omf/data_source_repo', 'vendor/d3/d3'], function(ds_repo) {
136
138
  var self = this;
137
139
  OHUB.bind(ds.event_name, function() {
138
140
  self.update();;
139
- })
141
+ });
140
142
  return ds;
141
143
  },
142
144
 
@@ -166,7 +168,7 @@ define(['omf/data_source_repo', 'vendor/d3/d3'], function(ds_repo) {
166
168
  _.map(properties_decl, function(a) {
167
169
  var pname = a[0]; var type = a[1]; var def = a[2];
168
170
  var descr = om[pname];
169
- m[pname] = self.create_mapping(pname, descr, source_name, type, def)
171
+ m[pname] = self.create_mapping(pname, descr, source_name, type, def);
170
172
  });
171
173
  return m;
172
174
  },
@@ -194,7 +196,7 @@ define(['omf/data_source_repo', 'vendor/d3/d3'], function(ds_repo) {
194
196
  create_mapping: function(mname, descr, stream, type, def) {
195
197
  var self = this;
196
198
  if (descr == undefined && typeof(def) == 'object') {
197
- descr = def
199
+ descr = def;
198
200
  }
199
201
  if (descr == undefined || typeof(descr) != 'object' ) {
200
202
  if (type == 'index') {
@@ -208,7 +210,7 @@ define(['omf/data_source_repo', 'vendor/d3/d3'], function(ds_repo) {
208
210
  var cf_i = cf();
209
211
  value = function(x) {
210
212
  return cf_i(x);
211
- }
213
+ };
212
214
  }
213
215
  return value;
214
216
  }
@@ -256,7 +258,7 @@ define(['omf/data_source_repo', 'vendor/d3/d3'], function(ds_repo) {
256
258
  var t = index_f(join);
257
259
  //var r = t[join];
258
260
  return t;
259
- }
261
+ };
260
262
  } else {
261
263
  if (descr.values) {
262
264
  // provided custom mapping for values
@@ -264,7 +266,7 @@ define(['omf/data_source_repo', 'vendor/d3/d3'], function(ds_repo) {
264
266
  var def_value = descr['default'];
265
267
  return function(x) {
266
268
  return values[x] || def_value;
267
- }
269
+ };
268
270
  }
269
271
  var pname = descr.property;
270
272
  if (pname == undefined) {
@@ -331,7 +333,7 @@ define(['omf/data_source_repo', 'vendor/d3/d3'], function(ds_repo) {
331
333
  if (source[prop] == null) {
332
334
  source[prop] = defaults[prop];
333
335
  } else if((typeof(source[prop]) == 'object') && defaults[prop]) {
334
- this.deep_defaults(source[prop], defaults[prop])
336
+ this.deep_defaults(source[prop], defaults[prop]);
335
337
  }
336
338
  }
337
339
  return source;
@@ -341,4 +343,4 @@ define(['omf/data_source_repo', 'vendor/d3/d3'], function(ds_repo) {
341
343
  });
342
344
 
343
345
  return abstract_widget;
344
- })
346
+ });
@@ -13,11 +13,11 @@ function omf_web_data_source(opts) {
13
13
  version: "0.1",
14
14
  name: name,
15
15
  schema: schema,
16
- rows: function() {return rows},
16
+ rows: function() { return rows; },
17
17
  index_for_column: index_for_column,
18
18
  is_dynamic: is_dynamic,
19
19
  event_name: event_name,
20
- }
20
+ };
21
21
 
22
22
  var indexes = {};
23
23
  var unique_index_check = null;
@@ -30,18 +30,18 @@ function omf_web_data_source(opts) {
30
30
  var index = indexes[i];
31
31
  if (!index) {
32
32
  index = indexes[i] = {};
33
- _.each(rows, function(r) { index[r[i]] = r; })
33
+ _.each(rows, function(r) { index[r[i]] = r; });
34
34
  }
35
35
  return function(key) {
36
36
  return indexes[i][key]; // need fresh lookup as we may redo index
37
- }
37
+ };
38
38
  }
39
39
 
40
40
  function update_indexes() {
41
41
  // This can most likley be done more efficiently if we consider what has changed
42
42
  _.each(indexes, function(ignore, i) {
43
43
  var index = indexes[i] = {};
44
- _.each(rows, function(r) { index[r[i]] = r; })
44
+ _.each(rows, function(r) { index[r[i]] = r; });
45
45
  });
46
46
  }
47
47
 
@@ -53,7 +53,7 @@ function omf_web_data_source(opts) {
53
53
  var opts = _;
54
54
  var interval = -1;
55
55
  if (typeof(opts) == 'number') {
56
- interval = opts
56
+ interval = opts;
57
57
  } else if (opts == true) {
58
58
  interval = 3;
59
59
  }
@@ -7,7 +7,7 @@ define(['omf/data_source3'], function(data_source) {
7
7
  function context() {};
8
8
 
9
9
  context.register = function(opts) {
10
- var id = opts.id || opts.name;
10
+ var id = opts.id || opts.stream || opts.name;
11
11
  if (sources[id] == null) {
12
12
  sources[id] = data_source(opts);
13
13
  }
@@ -19,7 +19,7 @@ define(['omf/data_source3'], function(data_source) {
19
19
  var dynamic = false;
20
20
 
21
21
  if (typeof(ds_descr) == 'object') {
22
- name = ds_descr.id || ds_descr.name;
22
+ name = ds_descr.id || ds_descr.stream || ds_descr.name;
23
23
  dynamic = ds_descr.dynamic;
24
24
  } else {
25
25
  name = ds_descr;