lanes 0.1.7 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/client/lanes/access/LoginDialog.coffee +0 -1
  3. data/client/lanes/access/screens/user-management/UserManagement.coffee +0 -1
  4. data/client/lanes/components/grid/Grid.coffee +7 -2
  5. data/client/lanes/components/radio-group/RadioGroup.coffee +0 -1
  6. data/client/lanes/components/record-finder/Clause.coffee +0 -1
  7. data/client/lanes/components/record-finder/Dialog.coffee +2 -2
  8. data/client/lanes/components/record-finder/RecordFinder.coffee +3 -2
  9. data/client/lanes/components/select2/Select2.coffee +8 -0
  10. data/client/lanes/components/select2/index.js +2 -0
  11. data/client/lanes/extension/Extensions.coffee +1 -1
  12. data/client/lanes/lib/ModuleSupport.coffee +1 -1
  13. data/client/lanes/models/ChangeSet.coffee +0 -1
  14. data/client/lanes/models/ModelAssociations.coffee +10 -10
  15. data/client/lanes/models/mixins/HasCodeField.coffee +3 -3
  16. data/client/lanes/screens/Definitions.coffee +0 -6
  17. data/client/lanes/views/ModelUpdate.coffee +0 -1
  18. data/client/lanes/workspace/ActiveScreensSwitcher.coffee +0 -1
  19. data/client/lanes/workspace/Layout.coffee +0 -1
  20. data/client/lanes/workspace/Navbar.coffee +0 -1
  21. data/client/lanes/workspace/Pages.coffee +0 -1
  22. data/client/lanes/workspace/ScreensMenu.coffee +0 -3
  23. data/lib/lanes/access/authentication_provider.rb +7 -7
  24. data/lib/lanes/api/coffeescript_processor.rb +64 -0
  25. data/lib/lanes/api/javascript_processor.rb +49 -41
  26. data/lib/lanes/api/root.rb +3 -1
  27. data/lib/lanes/concerns/pub_sub.rb +38 -40
  28. data/lib/lanes/configuration.rb +15 -9
  29. data/lib/lanes/version.rb +1 -1
  30. data/spec/command-reference-files/initial/Gemfile +1 -1
  31. data/spec/command-reference-files/initial/client/appy-app/Extension.coffee +0 -1
  32. data/spec/command-reference-files/model/client/appy-app/models/TestTest.coffee +0 -1
  33. data/spec/command-reference-files/screen/client/appy-app/screens/ready-set-go/ReadySetGo.coffee +0 -1
  34. data/spec/command-reference-files/screen/config/screens.rb +1 -0
  35. data/spec/command-reference-files/view/client/appy-app/views/BigView.coffee +0 -1
  36. data/spec/{api/javascript_processor_spec.rb → server/api/coffeescript_processor_spec.rb} +8 -2
  37. data/spec/server/concerns/pub_sub_spec.rb +55 -56
  38. data/templates/client/Extension.coffee +0 -1
  39. data/templates/client/models/Model.coffee +0 -1
  40. data/templates/client/screens/Screen.coffee +0 -1
  41. data/templates/client/views/View.coffee +0 -1
  42. data/templates/config/screen.rb +1 -0
  43. metadata +6 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 09c525f4869a2e1f8b1d4ff92ca1f31344715994
4
- data.tar.gz: 98893dd650c0d95209e9b337623f1c079e807ae6
3
+ metadata.gz: b111e3e03f3c6f6a3bfffca0d087590b1ea0277a
4
+ data.tar.gz: ac11d9b1700311f927f06d06bcbee08de31c56e2
5
5
  SHA512:
6
- metadata.gz: e8a11e0a3028195b5cf5bf3ff6f1e2cc06754e08e776100fcc69abf330cf1cadcf1c8e8b72d408b60f73266bd719feebc0d523b4415a847957cc7f9d947ef732
7
- data.tar.gz: a813d60b1ad735443aa90e5461743836f0eb606c81464e61e6d1131dc9e911fb5faba4a345ca876a474c3104205f360f19f1edaf0bb376bcbbe42b1f3fd56d91
6
+ metadata.gz: 3fd3233d6311c8df5041a5a39e2245f5e5099fbddde5126c8b4202e51bb79e51a25391bec8a18f9c51d13d3d34f66e7e22e5ce54a0fc88e42ea9e568bfe473ce
7
+ data.tar.gz: bd91444bafa49fc750fb6750071903a4856bff5ececf54c577935b55382788798f5b574f57b91fd41f56fb80bb5dece54b208fbc981e8b23f69d3519e0ce7d48
@@ -8,7 +8,6 @@ class Lanes.Access.LoginDialog extends Lanes.Components.ModalDialog
8
8
 
9
9
  size: 'md'
10
10
  title: 'Please sign in …'
11
- FILE: FILE
12
11
 
13
12
  domEvents:
14
13
  'click .btn-primary': 'onLogin'
@@ -2,7 +2,6 @@ class Lanes.Access.Screens.UserManagement extends Lanes.Screens.Base
2
2
 
3
3
  templateName: 'user-management/screen'
4
4
  templatePrefix: 'lanes/access/screens'
5
- FILE: FILE
6
5
 
7
6
  subviews:
8
7
  grid:
@@ -8,7 +8,6 @@ _.extend( Lanes.$.fn.dataTableExt.oStdClasses,{
8
8
 
9
9
 
10
10
  class Lanes.Components.Grid extends Lanes.Components.Base
11
- FILE: FILE
12
11
 
13
12
  domEvents:
14
13
  'click button.refresh': 'reload'
@@ -48,6 +47,7 @@ class Lanes.Components.Grid extends Lanes.Components.Base
48
47
  selectionMode: ['string', true, 'single']
49
48
  editorConfig: { type: 'object' }
50
49
  editingController: 'any' # either string or constructor fn
50
+ columnWidths: { type: 'array', default: -> [] }
51
51
 
52
52
  initialize: ->
53
53
  if this.viewport
@@ -191,7 +191,12 @@ class Lanes.Components.Grid extends Lanes.Components.Base
191
191
  align = switch query_field.type
192
192
  when 'integer','bigdec' then 'r'
193
193
  else 'l'
194
- { title: query_field.title, id: query_field.id, className: align, "targets": [ index ] }
194
+ options = {
195
+ id: query_field.id, title: query_field.title,
196
+ className: align, "targets": [ index ]
197
+ }
198
+ options['width'] = @columnWidths[index] if @columnWidths[index]
199
+ options
195
200
 
196
201
  _dataFromModel: (model)->
197
202
  data = []
@@ -17,7 +17,6 @@ class RadioInput extends Lanes.Views.Base
17
17
 
18
18
  class Lanes.Components.RadioGroup extends Lanes.Components.MultiSelect
19
19
 
20
- FILE: FILE
21
20
 
22
21
  writeTemplate: ->
23
22
  "<span data-hook='choices-input'></span>"
@@ -1,5 +1,4 @@
1
1
  class Lanes.Components.RecordFinder.Clause extends Lanes.Components.Base
2
- FILE: FILE
3
2
 
4
3
  writeTemplateName: 'clause'
5
4
  useFormBindings: true
@@ -1,5 +1,4 @@
1
1
  class Lanes.Components.RecordFinder.Dialog extends Lanes.Components.ModalDialog
2
- FILE: FILE
3
2
 
4
3
  domEvents:
5
4
  'click .add-clause': 'addClause'
@@ -12,7 +11,7 @@ class Lanes.Components.RecordFinder.Dialog extends Lanes.Components.ModalDialog
12
11
  hook: 'grid'
13
12
  component: 'Grid'
14
13
  options: ->
15
- { recordQuery: @recordQuery }
14
+ _.extend(@gridOptions||{}, { recordQuery: @recordQuery, options: @gridOptions })
16
15
  query_clauses:
17
16
  container: '.query-clauses'
18
17
  view: Lanes.Components.RecordFinder.Clause, collection: 'clauses'
@@ -22,6 +21,7 @@ class Lanes.Components.RecordFinder.Dialog extends Lanes.Components.ModalDialog
22
21
 
23
22
  session:
24
23
  recordQuery: 'model'
24
+ gridOptions: 'object'
25
25
  clauses: 'collection'
26
26
 
27
27
  initialize:(options)->
@@ -1,5 +1,4 @@
1
1
  class Lanes.Components.RecordFinder extends Lanes.Components.Base
2
- FILE: FILE
3
2
 
4
3
  writeTemplateName: 'field'
5
4
  writeTemplateData: ->
@@ -13,6 +12,7 @@ class Lanes.Components.RecordFinder extends Lanes.Components.Base
13
12
  withAssociations: 'array'
14
13
  invalid_chars: 'regex'
15
14
  recordQuery: 'model'
15
+ gridOptions: 'gridOptions'
16
16
  fieldName: 'string'
17
17
  queryField: [ 'string', false, 'code' ]
18
18
 
@@ -30,7 +30,8 @@ class Lanes.Components.RecordFinder extends Lanes.Components.Base
30
30
 
31
31
  displayFinder: ->
32
32
  finder = new Lanes.Components.RecordFinder.Dialog(
33
- parent:this, title: @title, recordQuery: @recordQuery
33
+ gridOptions: @gridOptions, parent:this
34
+ title: @title, recordQuery: @recordQuery
34
35
  )
35
36
  finder.show().then( (dlg)->
36
37
  dlg.remove().record
@@ -0,0 +1,8 @@
1
+ class Lanes.Components.Select2 extends Lanes.Components.Base
2
+
3
+ writeTemplate: ->
4
+ multiple = if this.multiple then "multiple" else ""
5
+ "<div><select class='form-control' #{multiple} name='#{this.field_name}' data-hook='choices-input'></select></div>"
6
+
7
+ readTemplate: ->
8
+ "<div class='ro-input' name='#{this.field_name}'></div>"
@@ -0,0 +1,2 @@
1
+ //= require ./template
2
+ //= require ./Select2
@@ -18,7 +18,7 @@ Lanes.Extensions = {
18
18
 
19
19
  makeNamespace: (identifier)->
20
20
  for ns in ['Models','Views','Controllers','Screens','Components']
21
- Lanes.namespace("#{identifier}.#{ns}")
21
+ Lanes.namespace("#{identifier}.#{ns}.Mixins")
22
22
 
23
23
  controlling: ->
24
24
  this.get( @controlling_id )
@@ -18,5 +18,5 @@ class Lanes.lib.ModuleSupport
18
18
  _.extend(@::[key], value)
19
19
  else
20
20
  @::[key] = value
21
- obj.included?.apply(@)
21
+ obj.included?(@)
22
22
  this
@@ -1,6 +1,5 @@
1
1
  class Lanes.Models.ChangeSet extends Lanes.Models.Base
2
2
 
3
- FILE: FILE
4
3
 
5
4
  constructor: ->
6
5
  super
@@ -15,7 +15,7 @@ class Lanes.Models.AssocationMap
15
15
  getClassFor: (name)->
16
16
  definition = @definitions[name]
17
17
  object = definition.model || definition.collection
18
- Lanes.u.findObject( object, 'Models', @klass::FILE)
18
+ Lanes.u.findObject(object, 'Models', @klass::FILE)
19
19
 
20
20
  getOptions: (name, definition, model)->
21
21
  options = { parent: model }
@@ -24,32 +24,32 @@ class Lanes.Models.AssocationMap
24
24
  options
25
25
 
26
26
  # will be called in the scope of the model
27
- createModel: (association, name, definition, fk, pk, target_klass)->
28
- target_klass ||= association.getClassFor(name)
27
+ createModel: (association, name, definition, fk, pk, target_class)->
28
+ target_class ||= association.getClassFor(name)
29
29
  options = association.getOptions(name,definition,this)
30
30
  model_id = this.get(pk)
31
31
  if model_id && model_id == this._cache[name]?.id
32
32
  this._cache[name]
33
33
  else
34
- target_klass.findOrCreate(options)
34
+ target_class.findOrCreate(options)
35
35
 
36
36
  # will be called in the scope of the model
37
- createCollection: (association, name, definition, fk, pk, target_klass)->
38
- target_klass ||= association.getClassFor(name)
37
+ createCollection: (association, name, definition, fk, pk, target_class)->
38
+ target_class ||= association.getClassFor(name)
39
39
  options = association.getOptions(name,definition,this)
40
40
  options.filter ||= {}
41
41
  options.filter[fk]=this.get(pk)
42
42
 
43
- if target_klass::isCollection
44
- new target_klass(options.models||[],options)
43
+ if target_class::isCollection
44
+ new target_class(options.models||[],options)
45
45
  else
46
- options.model=target_klass
46
+ options.model=target_class
47
47
  new Lanes.Models.AssociationCollection(options.models||[],options)
48
48
  # returns the definition for the derived property
49
49
  derivedDefinition: (name,definition)->
50
50
  createFn = _.partial(
51
51
  if definition.model then this.createModel else this.createCollection,
52
- this, name, definition, this.fk(name), this.pk(name), this.getClassFor(name)
52
+ this, name, definition, this.fk(name), this.pk(name)
53
53
  )
54
54
  { deps: [this.pk(name)], fn: createFn }
55
55
 
@@ -2,11 +2,11 @@ Lanes.Models.Mixins.HasCodeField = {
2
2
 
3
3
  INVALID: /[^A-Z0-9a-z]/
4
4
 
5
- included: ->
6
- this.prototype.INVALID_CODE_CLanes.RS ||= Lanes.Models.mixins.Lanes.sCodeField.INVALID
5
+ included: (klass)->
6
+ klass::INVALID_CODE_CHARS ||= Lanes.Models.mixins.Lanes.sCodeField.INVALID
7
7
 
8
8
  initialize: ->
9
- this.on('change:code', this.upcaseCode )
9
+ this.on('change:code', this.upcaseCode)
10
10
 
11
11
  upcaseCode: ->
12
12
  this.set('code', this.get('code').toUpperCase())
@@ -1,5 +1,4 @@
1
1
  class ScreenView extends Lanes.Models.BasicModel
2
- FILE: FILE
3
2
 
4
3
  session:
5
4
  screen: 'object'
@@ -31,7 +30,6 @@ class ScreenView extends Lanes.Models.BasicModel
31
30
 
32
31
 
33
32
  class ScreenDefinition extends Lanes.Models.BasicModel
34
- FILE: FILE
35
33
 
36
34
  session:
37
35
  id: 'string'
@@ -86,7 +84,6 @@ class ScreenDefinition extends Lanes.Models.BasicModel
86
84
 
87
85
 
88
86
  class ScreenViewSet extends Lanes.Models.BasicCollection
89
- FILE: FILE
90
87
 
91
88
  model: ScreenView
92
89
 
@@ -125,7 +122,6 @@ class ScreenViewSet extends Lanes.Models.BasicCollection
125
122
 
126
123
 
127
124
  class ScreenSet extends Lanes.Models.BasicCollection
128
- FILE: FILE
129
125
 
130
126
  model: ScreenDefinition
131
127
 
@@ -138,7 +134,6 @@ class ScreenSet extends Lanes.Models.BasicCollection
138
134
 
139
135
 
140
136
  class MenuGroup extends Lanes.Models.BasicModel
141
- FILE: FILE
142
137
 
143
138
  session:
144
139
  id: 'string'
@@ -156,7 +151,6 @@ class MenuGroup extends Lanes.Models.BasicModel
156
151
  })
157
152
 
158
153
  class MenuGroupSet extends Lanes.Models.BasicCollection
159
- FILE: FILE
160
154
 
161
155
  constructor: -> super
162
156
  model: MenuGroup
@@ -1,6 +1,5 @@
1
1
  class Lanes.Views.ModelUpdate extends Lanes.Views.Base
2
2
 
3
- FILE: FILE
4
3
 
5
4
  templateData: ->
6
5
  { change: @model }
@@ -1,7 +1,6 @@
1
1
  class TabView extends Lanes.Views.Base
2
2
 
3
3
  template: "<li><a data-toggle='tab'></a><span class='close'>×</span></li>"
4
- FILE: FILE
5
4
  mixins:[
6
5
  Lanes.Workspace.WorkspaceView
7
6
  ]
@@ -1,6 +1,5 @@
1
1
  class Lanes.Workspace.Layout extends Lanes.Views.Base
2
2
 
3
- FILE: FILE
4
3
  templateName: 'layout'
5
4
  templateData: ->
6
5
  { ui: this.ui_state }
@@ -1,7 +1,6 @@
1
1
  class Lanes.Workspace.Navbar extends Lanes.Views.Base
2
2
 
3
3
  templateName: 'navbar'
4
- FILE: FILE
5
4
  mixins:[
6
5
  Lanes.Workspace.WorkspaceView
7
6
  ]
@@ -1,7 +1,6 @@
1
1
  class Lanes.Workspace.Pages extends Lanes.Views.Base
2
2
 
3
3
  templateName: 'pages'
4
- FILE: FILE
5
4
  mixins:[
6
5
  Lanes.Workspace.WorkspaceView
7
6
  ]
@@ -1,7 +1,6 @@
1
1
  class ScreenList extends Lanes.Views.Base
2
2
 
3
3
  template: "<li><a href='#'><span></span><i></i></a></li>"
4
- FILE: FILE
5
4
  mixins:[
6
5
  Lanes.Workspace.WorkspaceView
7
6
  ]
@@ -19,7 +18,6 @@ class ScreenList extends Lanes.Views.Base
19
18
  class ScreenGroup extends Lanes.Views.Base
20
19
 
21
20
  template: '<li class="group"><a class="heading" href="#"><span></span><i></i></a><ul></ul></li>'
22
- FILE: FILE
23
21
  mixins:[
24
22
  Lanes.Workspace.WorkspaceView
25
23
  ]
@@ -47,7 +45,6 @@ class ScreenGroup extends Lanes.Views.Base
47
45
 
48
46
  class Lanes.Workspace.ScreensMenu extends Lanes.Views.Base
49
47
 
50
- FILE: FILE
51
48
  templateName: 'screens-menu'
52
49
  mixins:[
53
50
  Lanes.Workspace.WorkspaceView
@@ -10,10 +10,10 @@ module Lanes
10
10
 
11
11
  def current_user
12
12
  @current_user ||= (
13
- if Lanes.env.test? && request.env['HTTP_X_TESTING_USER']
13
+ if Lanes.env.test? && request.env['HTTP_X_TESTING_USER'].present?
14
14
  Lanes::User.where(login: request.env['HTTP_X_TESTING_USER']).first
15
15
  else
16
- Lanes::User.where(id: @session['user_id']).first
16
+ Lanes::User.where(id: request.session['user_id']).first
17
17
  end
18
18
  )
19
19
  end
@@ -23,7 +23,7 @@ module Lanes
23
23
  end
24
24
 
25
25
  def error_message_for_access
26
- return "Unable to " + case @request.request_method
26
+ return "Unable to " + case request.request_method
27
27
  when 'GET' then "read"
28
28
  when 'POST','PATCH','PUT' then "write"
29
29
  when 'DELETE' then "delete"
@@ -34,13 +34,13 @@ module Lanes
34
34
 
35
35
  def allowed_access_to?(klass)
36
36
  return false if current_user.nil?
37
- case @request.request_method
37
+ case request.request_method
38
38
  when 'GET'
39
- klass.can_read_attributes?(@request.params,current_user)
39
+ klass.can_read_attributes?(request.params,current_user)
40
40
  when 'POST','PATCH','PUT'
41
- klass.can_write_attributes?(@request.params,current_user)
41
+ klass.can_write_attributes?(request.params,current_user)
42
42
  when 'DELETE'
43
- klass.can_delete_attributes?(@request.params,current_user)
43
+ klass.can_delete_attributes?(request.params,current_user)
44
44
  else
45
45
  false
46
46
  end
@@ -0,0 +1,64 @@
1
+ # Coffeescript has two shortcomings with regards to Lanes
2
+ #
3
+ # The first is that it's extends format is incompatible with AmpersandState,
4
+ # State does quite a bit more via it's own .extend methods.
5
+ # Accordingly, we substitute our own "extend" call whenever we encounter a coffeescript extends
6
+ #
7
+ # The second issue is that if a constructor isn't present, coffeescript with generate it's own
8
+ # blank implementation that fails to call "super". We add a constructor that does call super if one's missing.
9
+
10
+ module Lanes
11
+ module API
12
+ class CoffeeScriptProcessor < JsAssetCompiler
13
+
14
+ class CoffeeClass
15
+ attr_reader :name, :extends, :contents, :file_contents, :indent
16
+ def initialize(name, extends, file_contents)
17
+ @name=name; @extends=extends; @file_contents=file_contents
18
+ file_contents.gsub!(/class\s+#{name}\s+.*?\n/,"class #{name}\n")
19
+ @contents = @file_contents[/(class #{name}\n.*?)(\n\w|\Z)/m,1]
20
+ @indent = @contents[/\n(\s+)(\w+):/,1] || ' '
21
+ end
22
+
23
+ def ensure_property(property_name, definition)
24
+ if contents !~ /^\s+#{property_name}\s*:/
25
+ # figure out how much to indent, sigh.
26
+ file_contents.gsub!(/class #{name}\n/,
27
+ "\\0#{indent}#{property_name}: #{definition}\n")
28
+ end
29
+ end
30
+
31
+ def save
32
+ file_contents.gsub!( /(class #{name}\n.*?)(\n\w|\Z)/m,
33
+ "\\1\n#{extends}.extend(#{name})\n\\2" )
34
+ end
35
+ end
36
+
37
+ self.registered_extension = '.coffee'
38
+
39
+ attr_reader :contents
40
+
41
+ CONSTRUCTOR = /constructor\s*:/
42
+
43
+ EXTENDING_CLASS_DEFINITION = /class\s+([\w|\.]+)\s+extends\s+([\w|\.]+)\s*?\n/
44
+
45
+ def cleaned
46
+ @contents = data.dup
47
+ data.scan(EXTENDING_CLASS_DEFINITION) do |match|
48
+ (name, extends) = match
49
+ cc = CoffeeClass.new(name, extends, contents)
50
+ cc.ensure_property("constructor", "-> super")
51
+ cc.ensure_property("FILE", "FILE")
52
+ cc.save
53
+ end
54
+ contents
55
+ end
56
+
57
+ def evaluate(scope, locals, &block)
58
+ wrap_js scope, ::CoffeeScript.compile(cleaned, bare: true)
59
+ end
60
+
61
+
62
+ end
63
+ end
64
+ end
@@ -40,47 +40,53 @@ module Lanes
40
40
 
41
41
  end
42
42
 
43
- class CoffeeScriptWrapper < JsAssetCompiler
44
- self.registered_extension = '.coffee'
45
-
46
- CONSTRUCTOR = /constructor\s*:/
47
- EXTENDING_CLASS = /class\s+([\w|\.]+)\s+extends\s+([\w|\.]+)\s*?\n/
48
-
49
- # Coffeescript has two shortcomings with regards to Lanes
50
- #
51
- # The first is that it's extends format is incompatible with AmpersandState,
52
- # State does quite a bit more via it's own .extend methods.
53
- # Accordingly, we substitute our own "extend" call whenever we encounter a coffeescript extends
54
- #
55
- # The second issue is that if a constructor isn't present, coffeescript with generate it's own
56
- # blank implementation that fails to call "super". We add a constructor that does call super if one's missing.
57
-
58
- def cleaned
59
- contents = data.dup
60
- data.scan(EXTENDING_CLASS) do |match|
61
- (name,extends) = match
62
-
63
- contents.gsub!(/class\s+#{name}\s+.*?\n/,"class #{name}\n")
64
- definition = contents[/(class #{name}\n.*?)(\n\w|\Z)/m,1]
65
- # is it missing a constructor?
66
- if definition !~ /constructor:/
67
- # figure out how much to indent, sigh.
68
- indent = definition[/\n(\s+)(\w+):/,1] || ' '
69
- contents.gsub!(/class #{name}\n/,"\\0#{indent}constructor: -> super\n")
70
-
71
- end
72
- contents.gsub!( /(class #{name}\n.*?)(\n\w|\Z)/m, "\\1\n#{extends}.extend(#{name})\n\\2" )
73
-
74
- contents
75
- #contents << "#{extends}.extend(#{name})\n"
76
- end
77
- contents
78
- end
79
-
80
- def evaluate(scope, locals, &block)
81
- wrap_js scope, ::CoffeeScript.compile(cleaned, bare: true)
82
- end
83
- end
43
+ # class CoffeeScriptWrapper < JsAssetCompiler
44
+ # self.registered_extension = '.coffee'
45
+
46
+ # CONSTRUCTOR = /constructor\s*:/
47
+ # CLASS_DEFINITION = /\s*class\s+([\w|\.]+)/
48
+ # EXTENDING_CLASS = /class\s+([\w|\.]+)\s+extends\s+([\w|\.]+)\s*?\n/
49
+
50
+ # # Coffeescript has two shortcomings with regards to Lanes
51
+ # #
52
+ # # The first is that it's extends format is incompatible with AmpersandState,
53
+ # # State does quite a bit more via it's own .extend methods.
54
+ # # Accordingly, we substitute our own "extend" call whenever we encounter a coffeescript extends
55
+ # #
56
+ # # The second issue is that if a constructor isn't present, coffeescript with generate it's own
57
+ # # blank implementation that fails to call "super". We add a constructor that does call super if one's missing.
58
+
59
+ # def cleaned
60
+ # contents = data.dup
61
+ # data.scan(CLASS_DEFINITION) do |match|
62
+ # (name, extends) = match
63
+ # definition = get_definition(name)
64
+
65
+
66
+ # # is it missing a constructor?
67
+ # if definition !~ /constructor:/
68
+ # # figure out how much to indent, sigh.
69
+ # indent = definition[/\n(\s+)(\w+):/,1] || ' '
70
+ # contents.gsub!(/class #{name}\n/,"\\0#{indent}constructor: -> super\n")
71
+
72
+ # end
73
+ # contents.gsub!( /(class #{name}\n.*?)(\n\w|\Z)/m, "\\1\n#{extends}.extend(#{name})\n\\2" )
74
+
75
+ # contents
76
+ # #contents << "#{extends}.extend(#{name})\n"
77
+ # end
78
+ # contents
79
+ # end
80
+
81
+ # def evaluate(scope, locals, &block)
82
+ # wrap_js scope, ::CoffeeScript.compile(cleaned, bare: true)
83
+ # end
84
+
85
+ # def get_definition(name)
86
+ # contents.gsub!(/class\s+#{name}\s+.*?\n/,"class #{name}\n")
87
+ # definition = contents[/(class #{name}\n.*?)(\n\w|\Z)/m,1]
88
+ # end
89
+ # end
84
90
 
85
91
  class Es6Compiler < JsAssetCompiler
86
92
  self.registered_extension = '.es6'
@@ -129,3 +135,5 @@ module Lanes
129
135
 
130
136
  end
131
137
  end
138
+
139
+ require_relative 'coffeescript_processor'
@@ -35,7 +35,9 @@ module Lanes
35
35
  PubSub.initialize(self)
36
36
  Extensions.load_controlling_config
37
37
  # late load in case an extension has provided an alternative implementation
38
- require "lanes/api/null_authentication_provider" unless API.const_defined?(:AuthenticationProvider)
38
+ unless API.const_defined?(:AuthenticationProvider)
39
+ require "lanes/api/null_authentication_provider"
40
+ end
39
41
  # use Rack::Csrf, :skip=>['GET:/'], :raise => true
40
42
  end
41
43
 
@@ -1,6 +1,6 @@
1
1
  module Lanes::Concerns
2
2
 
3
- # Event subscription and publishing for Stockor Models
3
+ # Event subscription and publishing for Models
4
4
  # Every model has certain built-in events (:save, :create, :update, :destroy)
5
5
  # And may also implement custom events that reflect the models domain
6
6
  # @example Send an email when a customer's name is updated
@@ -50,31 +50,37 @@ module Lanes::Concerns
50
50
  class_attribute :_event_listeners
51
51
  base.valid_event_names = [ :save, :create, :update, :destroy ]
52
52
 
53
- base.after_save :fire_after_save_events
54
- base.after_create :fire_after_create_events
55
- base.after_update :fire_after_update_events
56
- base.after_destroy :fire_after_destroy_events
53
+ base.after_save :fire_after_save_pubsub_events
54
+ base.after_create :fire_after_create_pubsub_events
55
+ base.after_update :fire_after_update_pubsub_events
56
+ base.after_destroy :fire_after_destroy_pubsub_events
57
57
  end
58
58
 
59
59
  module ClassMethods
60
60
  def inherited(base)
61
61
  super
62
62
  klass = base.to_s.demodulize
63
-
64
- #p klass
65
- # if klass=="Tester"
66
- # binding.pry
67
- # end
68
63
  events = PubSub::PendingListeners.claim( klass )
69
- events.each{ | name, procs | base.event_listeners[name] += procs }
70
-
64
+ events.each{ | name, procs |
65
+ procs.each{|pr|
66
+ base.send(:_add_event_listener, name, &pr)
67
+ }
68
+ }
71
69
  end
72
70
 
73
71
  def observe( event, &block )
74
- _ensure_validate_event( event )
72
+ unless self.valid_event_names.include?(event.to_sym)
73
+ raise InvalidEvent.new("#{event} is not a valid event for #{self}")
74
+ end
75
75
  _add_event_listener( event.to_sym, &block )
76
76
  end
77
77
 
78
+ protected
79
+
80
+ def has_additional_events( *names )
81
+ self.valid_event_names += names.map{ |name| name.to_sym }
82
+ end
83
+
78
84
  private
79
85
 
80
86
  def _add_event_listener(name, &block)
@@ -84,46 +90,38 @@ module Lanes::Concerns
84
90
  self._event_listeners = self._event_listeners.dup
85
91
  self._event_listeners[name] = listeners
86
92
  end
87
-
88
- def _ensure_validate_event(event)
89
- unless self.valid_event_names.include?(event.to_sym)
90
- raise InvalidEvent.new("#{event} is not a valid event for #{self}")
91
- end
92
- end
93
-
94
- def has_additional_events( *names )
95
- self.valid_event_names += names.map{ |name| name.to_sym }
96
- end
97
93
  end
98
94
 
99
95
  protected
100
96
 
101
- def fire_after_destroy_events
102
- _fire_event(:update, self )
97
+ def fire_after_destroy_pubsub_events
98
+ fire_pubsub_event(:update, self)
103
99
  end
104
- def fire_after_update_events
105
- _fire_event(:update, self )
100
+
101
+ def fire_after_update_pubsub_events
102
+ fire_pubsub_event(:update, self)
106
103
  end
107
- def fire_after_create_events
108
- _fire_event(:create, self )
104
+
105
+ def fire_after_create_pubsub_events
106
+ fire_pubsub_event(:create, self)
109
107
  end
110
- def fire_after_save_events
111
- _fire_event( :save, self )
108
+
109
+ def fire_after_save_pubsub_events
110
+ fire_pubsub_event(:save, self)
112
111
  end
113
112
 
114
- def fire_event( name, *arguments )
115
- self.class._ensure_validate_event( name )
116
- arguments.unshift( self )
117
- _fire_event( name, *arguments )
113
+ def fire_pubsub_event(name, *arguments)
114
+ return if self.class._event_listeners.nil? ||
115
+ !self.class._event_listeners.has_key?(name.to_sym)
116
+ arguments = arguments.dup.unshift(self)
117
+ self.class._event_listeners[ name.to_sym ].each{ | block |
118
+ block.call(*arguments)
119
+ }
118
120
  end
119
121
 
120
122
  private
121
123
 
122
- def _fire_event( name, *arguments )
123
- return if self.class._event_listeners.nil? ||
124
- !self.class._event_listeners.has_key?(name.to_sym)
125
-
126
- self.class._event_listeners[ name.to_sym ].each{ | block | block.call(*arguments) }
124
+ def _fire_pubsub_event( name, *arguments )
127
125
  end
128
126
  end
129
127
 
@@ -51,25 +51,31 @@ module Lanes
51
51
  # Database tables will have this prefix applied to them
52
52
  config_option :table_prefix, ''
53
53
 
54
- config_option :debug_assets, false
55
- config_option :default_javascript_tag_options, {}
56
-
54
+ # The configuration environment to use, test, development, production
57
55
  config_option :environment, (ENV['RACK_ENV'] || 'development').to_sym
56
+
58
57
  # The secret key to use for session cookies.
59
58
  config_option :session_secret_key_base, '1234', silent: true
59
+
60
+ # Configuration for Redis
60
61
  config_option :redis, { path: "/tmp/redis.sock" }
61
- config_option :pubsub_key, nil
62
- config_option :pubsub_host, nil
63
- config_option :pubsub_timeout, 10
64
62
 
65
- config_option :es6_transpiler_path, '6to5'
66
- config_option :es6_transpiler_options, '-t '
63
+ # Title of application
67
64
  config_option :app_title, "Lanes Test"
65
+
66
+ # url prefix to use for assets
68
67
  config_option :assets_path_prefix, "/assets"
68
+
69
+ # prefix to use for all urls
69
70
  config_option :mounted_at, ''
71
+
72
+ # The initial view class to display
70
73
  config_option :root_view, 'Lanes.Workspace.Layout'
74
+
75
+ # Screen to display on load (if workspace extension is used)
71
76
  config_option :initial_workspace_screen_id, ''
72
- config_option :specs_root, Pathname.getwd
77
+
78
+ # types of assets to include into compiled package
73
79
  config_option :static_asset_types, ['images','fonts']
74
80
  end
75
81
 
data/lib/lanes/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Lanes
2
2
 
3
- VERSION = "0.1.7"
3
+ VERSION = "0.1.8"
4
4
 
5
5
  end
@@ -1,6 +1,6 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem "lanes", '0.1.6'
3
+ gem "lanes", '0.1.8'
4
4
 
5
5
  gem "rake"
6
6
  gem 'puma'
@@ -1,6 +1,5 @@
1
1
  class AppyApp.Extension extends Lanes.Extensions.Base
2
2
 
3
- FILE: FILE
4
3
 
5
4
  identifier: "appy-app"
6
5
 
@@ -1,6 +1,5 @@
1
1
  class AppyApp.Models.TestTest extends AppyApp.Models.Base
2
2
 
3
- FILE: FILE
4
3
 
5
4
  props:
6
5
  id : "integer"
@@ -1,6 +1,5 @@
1
1
  class AppyApp.Screens.ReadySetGo extends AppyApp.Screens.Base
2
2
 
3
- FILE: FILE
4
3
 
5
4
  subviews: {}
6
5
 
@@ -1,4 +1,5 @@
1
1
  Lanes::Screen.define "ready-set-go" do | screen |
2
+ screen.title = "Ready Set Go"
2
3
  screen.description = ""
3
4
  screen.icon = ""
4
5
  screen.group_id = ""
@@ -1,6 +1,5 @@
1
1
  class AppyApp.Views.BigView extends AppyApp.Views.Base
2
2
 
3
- FILE: FILE
4
3
 
5
4
  ## These are listed only as examples.
6
5
  # If unused they can be safely removed.
@@ -1,6 +1,6 @@
1
1
  require "lanes/spec_helper"
2
2
 
3
- class JavascriptProcessorTest < Lanes::TestCase
3
+ class CoffeeScriptProcessor < Lanes::TestCase
4
4
 
5
5
  SCRIPT = <<-EOS
6
6
  class NS.Baz
@@ -30,6 +30,7 @@ class NS.Baz
30
30
  alert(msg);
31
31
 
32
32
  class NS.Bar
33
+ FILE: FILE
33
34
  constructor: -> super
34
35
  squawk:->
35
36
  this.alert("Hello World!")
@@ -37,6 +38,7 @@ class NS.Bar
37
38
  NS.Baz.extend(NS.Bar)
38
39
 
39
40
  class Foo
41
+ FILE: FILE
40
42
  constructor: ->
41
43
  this.called=true
42
44
  super
@@ -65,6 +67,8 @@ NS.Baz = (function() {
65
67
  })();
66
68
 
67
69
  NS.Bar = (function() {
70
+ Bar.prototype.FILE = FILE;
71
+
68
72
  function Bar() {
69
73
  Bar.__super__.constructor.apply(this, arguments);
70
74
  }
@@ -80,6 +84,8 @@ NS.Bar = (function() {
80
84
  NS.Baz.extend(NS.Bar);
81
85
 
82
86
  Foo = (function() {
87
+ Foo.prototype.FILE = FILE;
88
+
83
89
  function Foo() {
84
90
  this.called = true;
85
91
  Foo.__super__.constructor.apply(this, arguments);
@@ -101,7 +107,7 @@ EOS
101
107
  Scope = Struct.new(:logical_path)
102
108
 
103
109
  def test_coffeescript_generation
104
- template = API::CoffeeScriptWrapper.new{ |t| SCRIPT }
110
+ template = API::CoffeeScriptProcessor.new{ |t| SCRIPT }
105
111
  assert_equal CLEANED, template.cleaned
106
112
 
107
113
 
@@ -5,123 +5,122 @@ describe "PubSub" do
5
5
  include ActiveRecordMocks::IncludeMe
6
6
  around do | test |
7
7
  with_mocked_tables do |m|
8
- m.create_table do |t|
9
- t.model_name :Evbt
10
- t.belongs_to :evhm, class_name: "Evhm", listen: { create: 'on_create_hm' },
11
- inverse_of: :evbt
12
- t.layout do |l|
13
- l.integer :evhm_id
14
- end
15
- t.parent_class "Lanes::Model"
16
- end
17
- class Evbt
8
+
9
+ class A < Lanes::Model
18
10
  has_additional_events :test_one
19
- def on_create_hm(*args)
20
- 32
11
+ def on_save_b(*args)
12
+ end
13
+ def on_save_event_tester(*args)
21
14
  end
22
15
  end
23
-
24
16
  m.create_table do |t|
25
- t.model_name :EventTester
17
+ t.model_name :A
26
18
  t.parent_class "Lanes::Model"
27
- t.belongs_to :evbt, class_name: 'Evhm'
19
+ t.belongs_to :b_model, class_name: "B", listen: { save: :on_save_b },
20
+ inverse_of: :a_model
28
21
 
29
- t.has_many :evhm, class_name: 'Evhm', inverse_of: :event_tester
22
+ t.belongs_to :event_tester, class_name: "EventTester", inverse_of: :a_models,
23
+ listen: { save: 'on_save_event_tester' }
30
24
 
31
25
  t.layout do |l|
32
- l.integer :bt_id
33
- l.string :name, :number
26
+ l.integer :b_model_id, :b_id
27
+ l.integer :event_tester_id
34
28
  end
35
29
  end
36
30
 
31
+ class B < Lanes::Model
32
+ def on_save_a(*args)
33
+ end
34
+ end
37
35
  table = m.create_table do |t|
38
- t.model_name :Evhm
39
- t.belongs_to :evbt, class_name: "Evbt", listen: { save: 'on_create_bt' },
40
- inverse_of: :evhm
41
- t.belongs_to :event_tester, class_name: "EventTester", inverse_of: :evhm,
42
- listen: { save: 'on_save_event_tester' }
36
+ t.model_name :B
43
37
  t.parent_class "Lanes::Model"
38
+ t.has_one :a_model, class_name: "A", listen: { save: 'on_save_a' },
39
+ inverse_of: :b_model
44
40
  t.layout do | l |
45
41
  l.string :mumble
46
- l.integer :evbt_id, :event_tester_id
47
42
  end
48
43
  end
49
- def table.on_save_event_tester(*args)
44
+
45
+ class EventTester < Lanes::Model
50
46
  end
51
47
 
48
+ m.create_table do |t|
49
+ t.model_name :EventTester
50
+ t.parent_class "Lanes::Model"
51
+ t.has_many :a_models, class_name: 'A', inverse_of: :event_tester
52
52
 
53
+ t.layout do |l|
54
+ l.string :name, :number
55
+ end
56
+ end
53
57
 
54
58
  test.call
59
+
55
60
  end
56
61
  end
57
62
 
58
63
  it "listens to other associations" do
59
- e=Evbt.new
60
- assert_equal 32, e.on_create_hm
61
- b=e.build_evhm
62
- b.expects(:on_create_bt)
63
- assert e.save
64
+ a=A.new
65
+ b=a.build_b_model
66
+ assert b.a_model
67
+ a.expects(:on_save_b)
68
+ assert a.save
64
69
 
65
70
  et = EventTester.new
66
- evh = et.evhm.build
67
- evh.expects(:on_save_event_tester)
68
- assert et.save
71
+ a=et.a_models.build
72
+ a.expects(:on_save_event_tester)
73
+ et.save
69
74
  end
70
75
 
71
76
  it "registers" do
72
- assert_equal [ :save, :create, :update, :destroy ],EventTester.valid_event_names
73
- assert_equal [ :save, :create, :update, :destroy, :test_one ],Evbt.valid_event_names
77
+ assert_equal [ :save, :create, :update, :destroy ], EventTester.valid_event_names
78
+ assert_equal [ :save, :create, :update, :destroy, :test_one ], A.valid_event_names
74
79
  end
75
80
 
76
81
  it "can only observe valid events" do
77
- assert_raises( EventTester::InvalidEvent) do
82
+ assert_raises(EventTester::InvalidEvent) do
78
83
  EventTester.observe(:invalid_event) do | ev |
79
84
  end
80
85
  end
81
- assert_raises( EventTester::InvalidEvent) do
82
- EventTester.observe(:save) do | ev |
86
+ assert_raises(EventTester::InvalidEvent) do
87
+ B.observe(:test_two) do | ev |
83
88
  end
84
- EventTester.new.send(:fire_event,:invalid_event)
85
89
  end
86
- assert_raises( EventTester::InvalidEvent) do
87
- Evbt.observe(:test_two) do | ev |
88
- end
89
- end
90
- assert_raises( EventTester::InvalidEvent) do
91
- Evhm.observe(:test_one) do | ev |
90
+ assert_raises(EventTester::InvalidEvent) do
91
+ A.observe(:glub_glub) do | ev |
92
92
  end
93
93
  end
94
94
  begin
95
- Evbt.observe(:test_one) do | ev |
95
+ B.observe(:test_one) do | ev |
96
96
  end
97
97
  rescue EventTester::InvalidEvent=>e
98
- assert_equal 'test_one is not a valid event for PubSubTest::Ev2', e.to_s
98
+ assert_equal 'test_one is not a valid event for B', e.to_s
99
99
  end
100
100
  end
101
101
 
102
102
  it "events can be subscribed to" do
103
103
  EventTester.observe(:save) do | ev |
104
-
105
104
  end
106
105
  end
107
106
 
108
107
  it "can be fired and observed" do
109
108
  results=[]
110
- Evbt.observe(:test_one) do | ev, one, two |
109
+ A.observe(:test_one) do | ev, one, two |
111
110
  results = [ ev, one, two ]
112
111
  end
113
- evt=Evbt.new
114
- evt.send(:fire_event, :test_one, 3, 5 )
115
- assert_equal [ evt, 3, 5 ], results
112
+ a=A.new
113
+ a.send(:fire_pubsub_event, :test_one, 3, 5 )
114
+ assert_equal [a, 3, 5], results
116
115
 
117
- evt.send(:fire_event, :test_one, 'foo' )
118
- assert_equal [ evt, 'foo', nil ], results
116
+ a.send(:fire_pubsub_event, :test_one, 'foo' )
117
+ assert_equal [a, 'foo', nil], results
119
118
  end
120
119
 
121
120
 
122
121
  it "can use custom event assertions" do
123
- assert_event_fires( Evbt, :test_one ) do
124
- Evbt.new.send(:fire_event, :test_one, 3, 5 )
122
+ assert_event_fires(A, :test_one) do
123
+ A.new.send(:fire_pubsub_event, :test_one, 3, 5)
125
124
  end
126
125
  assert_equal [ 3, 5 ], last_event_results[1..-1]
127
126
  end
@@ -1,6 +1,5 @@
1
1
  class <%= namespace %>.Extension extends Lanes.Extensions.Base
2
2
 
3
- FILE: FILE
4
3
 
5
4
  identifier: "<%= identifier %>"
6
5
 
@@ -1,6 +1,5 @@
1
1
  class <%= namespace %>.Models.<%= class_name %> extends <%= namespace %>.Models.Base
2
2
 
3
- FILE: FILE
4
3
 
5
4
  props:
6
5
  <% fields.each do |field| -%>
@@ -1,6 +1,5 @@
1
1
  class <%= namespace.camelize %>.Screens.<%= class_name %> extends <%= namespace.camelize %>.Screens.Base
2
2
 
3
- FILE: FILE
4
3
  <% if @template -%>
5
4
  template: '''
6
5
  <%= @template %>
@@ -1,6 +1,5 @@
1
1
  class <%= namespace %>.Views.<%= class_name %> extends <%= namespace %>.Views.Base
2
2
 
3
- FILE: FILE
4
3
 
5
4
  ## These are listed only as examples.
6
5
  # If unused they can be safely removed.
@@ -1,4 +1,5 @@
1
1
  Lanes::Screen.define "<%= screen_id %>" do | screen |
2
+ screen.title = "<%= options[:title] %>"
2
3
  screen.description = "<%= options[:description] %>"
3
4
  screen.icon = "<%= options[:icon] %>"
4
5
  screen.group_id = "<%= options[:group] %>"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lanes
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nathan Stitt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-17 00:00:00.000000000 Z
11
+ date: 2015-03-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -527,6 +527,8 @@ files:
527
527
  - client/lanes/components/select-field/SelectField.coffee
528
528
  - client/lanes/components/select-field/index.js
529
529
  - client/lanes/components/select-field/styles.scss
530
+ - client/lanes/components/select2/Select2.coffee
531
+ - client/lanes/components/select2/index.js
530
532
  - client/lanes/extension/Base.coffee
531
533
  - client/lanes/extension/EarlyExtensions.js.erb
532
534
  - client/lanes/extension/Extensions.coffee
@@ -810,6 +812,7 @@ files:
810
812
  - lib/lanes/access/user.rb
811
813
  - lib/lanes/access/version.rb
812
814
  - lib/lanes/api.rb
815
+ - lib/lanes/api/coffeescript_processor.rb
813
816
  - lib/lanes/api/controller.rb
814
817
  - lib/lanes/api/eco.js
815
818
  - lib/lanes/api/error_formatter.rb
@@ -886,7 +889,6 @@ files:
886
889
  - npm-build/package.json
887
890
  - npm-build/shims/underscore.js
888
891
  - npm-build/template.js
889
- - spec/api/javascript_processor_spec.rb
890
892
  - spec/command-reference-files/initial/.gitignore
891
893
  - spec/command-reference-files/initial/Gemfile
892
894
  - spec/command-reference-files/initial/Guardfile
@@ -943,6 +945,7 @@ files:
943
945
  - spec/lanes/models/PubSubSpec.coffee
944
946
  - spec/lanes/views/BaseSpec.coffee
945
947
  - spec/lanes/views/FormBindingsSpec.coffee
948
+ - spec/server/api/coffeescript_processor_spec.rb
946
949
  - spec/server/command_spec.rb
947
950
  - spec/server/concerns/api_path_spec.rb
948
951
  - spec/server/concerns/association_extensions_spec.rb