omf_web 1.2.1 → 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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;