luca 0.9.6 → 0.9.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. data/CHANGELOG +37 -14
  2. data/lib/luca/rails/version.rb +1 -1
  3. data/spec/components/collection_view_spec.coffee +24 -2
  4. data/spec/components/pagination_control_spec.coffee +0 -0
  5. data/spec/concerns/dom_helpers_spec.coffee +16 -0
  6. data/spec/concerns/filterable_spec.coffee +25 -0
  7. data/spec/concerns/model_presenter_spec.coffee +31 -0
  8. data/spec/concerns/paginatable_spec.coffee +0 -0
  9. data/spec/concerns/state_model_spec.coffee +0 -0
  10. data/spec/concerns_spec.coffee +88 -0
  11. data/spec/core/container_spec.coffee +74 -12
  12. data/spec/core/model_spec.coffee +6 -1
  13. data/spec/define_spec.coffee +0 -6
  14. data/spec/util_spec.coffee +24 -0
  15. data/src/components/application.coffee +32 -30
  16. data/src/components/base_toolbar.coffee +6 -4
  17. data/src/components/collection_loader_view.coffee +3 -1
  18. data/src/components/collection_view.coffee +42 -21
  19. data/src/components/controller.coffee +3 -1
  20. data/src/components/fields/button_field.coffee +19 -12
  21. data/src/components/fields/checkbox_array.coffee +8 -2
  22. data/src/components/fields/checkbox_field.coffee +18 -9
  23. data/src/components/fields/file_upload_field.coffee +5 -1
  24. data/src/components/fields/hidden_field.coffee +3 -1
  25. data/src/components/fields/label_field.coffee +4 -3
  26. data/src/components/fields/select_field.coffee +7 -8
  27. data/src/components/fields/text_field.coffee +3 -1
  28. data/src/components/fields/type_ahead_field.coffee +4 -2
  29. data/src/components/form_button_toolbar.coffee +4 -1
  30. data/src/components/form_view.coffee +49 -44
  31. data/src/components/grid_view.coffee +1 -1
  32. data/src/components/multi_collection_view.coffee +49 -22
  33. data/src/components/pagination_control.coffee +17 -13
  34. data/src/{modules → concerns}/application_event_bindings.coffee +1 -1
  35. data/src/{modules → concerns}/collection_event_bindings.coffee +1 -1
  36. data/src/{modules → concerns}/deferrable.coffee +1 -1
  37. data/src/{modules → concerns}/dom_helpers.coffee +11 -2
  38. data/src/{modules → concerns}/enhanced_properties.coffee +1 -1
  39. data/src/concerns/filterable.coffee +82 -0
  40. data/src/{modules → concerns}/grid_layout.coffee +1 -1
  41. data/src/{modules → concerns}/loadmaskable.coffee +1 -1
  42. data/src/{modules → concerns}/local_storage.coffee +0 -0
  43. data/src/{modules → concerns}/modal_view.coffee +1 -1
  44. data/src/concerns/model_presenter.coffee +23 -0
  45. data/src/concerns/paginatable.coffee +87 -0
  46. data/src/{modules → concerns}/state_model.coffee +1 -1
  47. data/src/{modules → concerns}/templating.coffee +1 -1
  48. data/src/concerns.coffee +70 -0
  49. data/src/containers/tab_view.coffee +7 -10
  50. data/src/core/collection.coffee +17 -1
  51. data/src/core/container.coffee +56 -31
  52. data/src/core/field.coffee +39 -38
  53. data/src/core/meta_data.coffee +37 -0
  54. data/src/core/model.coffee +18 -1
  55. data/src/core/view.coffee +25 -29
  56. data/src/define.coffee +54 -66
  57. data/src/framework.coffee +23 -18
  58. data/src/index.coffee +3 -1
  59. data/src/stylesheets/components/checkbox_array.scss +1 -1
  60. data/src/stylesheets/components/form_view.scss +5 -5
  61. data/src/stylesheets/components/viewport.scss +2 -1
  62. data/src/stylesheets/containers/container.scss +0 -5
  63. data/src/stylesheets/containers/tab_view.scss +5 -5
  64. data/src/tools/console.coffee +5 -5
  65. data/src/util.coffee +47 -0
  66. data/vendor/assets/javascripts/luca-ui-development-tools.js +5 -5
  67. data/vendor/assets/javascripts/luca-ui-development-tools.min.js +1 -1
  68. data/vendor/assets/javascripts/luca-ui-full.js +905 -416
  69. data/vendor/assets/javascripts/luca-ui-full.min.js +5 -5
  70. data/vendor/assets/javascripts/luca-ui.js +905 -416
  71. data/vendor/assets/javascripts/luca-ui.min.js +5 -4
  72. data/vendor/assets/stylesheets/luca-ui.css +15 -15
  73. metadata +27 -17
  74. data/spec/mixin_spec.coffee +0 -49
  75. data/src/modules/filterable.coffee +0 -60
  76. data/src/modules/paginatable.coffee +0 -79
data/CHANGELOG CHANGED
@@ -85,26 +85,26 @@
85
85
  0.9.1
86
86
  - Bugfix Release
87
87
 
88
- 0.9.2
88
+ 0.9.2
89
89
  - FormView has errorMessage, successMessage methods which use twitter bootstrap alerts as flash message
90
90
  - FormView toolbar accepts new options: true, both, bottom, or top
91
91
  - Luca.Collection has a property @remoteFiltering which makes applyFilter always use remote fetch
92
92
  - Bugfix in GridView collection change handler
93
93
  - Added Luca.isViewPrototype, Luca.isModelPrototype, Luca.isCollectionPrototype helpers
94
94
  - Added configuration option to control auto registration of components with the registry
95
- - Added Luca.parentClass and Luca.inheritanceChain methods for inspecting a component or prototype
95
+ - Added Luca.parentClass and Luca.inheritanceChain methods for inspecting a component or prototype
96
96
  - Changed single instance tracking mechanism on CollectionManager. Will throw an error if more than one
97
97
  is created without specifying a name.
98
98
  - Added Luca.getCollectionManager() helper as an Alias for Luca.CollectionManager.get()
99
99
  - Luca.getApplication() and Luca.getCollectionManager() accept a name argument
100
100
  - Classes like Luca.Application and Luca.CollectionManager which normally are singletons
101
- can have more than one instance if a unique name is given
101
+ can have more than one instance if a unique name is given
102
102
 
103
103
  0.9.3
104
104
  - CardViews and Controllers set data attributes on their elements for the active card / page
105
105
  - Added convenience methods to container 'pluck', 'invoke'
106
106
  - Added methods to Controller for ease of autogenerating routes
107
- - Added beforeInitialize hook on Luca.View
107
+ - Added beforeInitialize hook on Luca.View
108
108
  - Luca.View can now automatically configure state machine models by passing `stateful:true`
109
109
  in your view definition.
110
110
  - Containers will respond to getter attributes set on their components, by defining a getter
@@ -118,9 +118,9 @@
118
118
  - adding a Luca.PageController component as an alias for Controller
119
119
 
120
120
  0.9.33
121
- - added gridSpan property to Luca.View. This will automatically add the span class for you to snap your view to the grid.
121
+ - added gridSpan property to Luca.View. This will automatically add the span class for you to snap your view to the grid.
122
122
  Accepts a number 0-12.
123
- - fixed a bug in CardView.componentElements method with bodyClassName being present
123
+ - fixed a bug in CardView.componentElements method with bodyClassName being present
124
124
  - Added LabelView component. A form field which just displays a value.
125
125
 
126
126
  0.9.35
@@ -134,14 +134,14 @@
134
134
 
135
135
  0.9.4
136
136
  - Luca::Template can now configure its namespace, removing duplicate sprockets class
137
- - Luca.Application triggers page:change and sub:page:change events
137
+ - Luca.Application triggers page:change and sub:page:change events
138
138
  - Luca.Viewport gets enable / disable method for fluid and fullscreen mode
139
139
  - Add configurability to fullscreen behavior on viewport
140
140
 
141
141
  0.9.41
142
142
  - Changed asset pipeline payload so that luca-ui uses the index convention
143
143
 
144
- 0.9.42
144
+ 0.9.42
145
145
  - Added TableView component, which inherits from Luca.components.CollectionView
146
146
  - Expose ways of customizing Luca.View internals.
147
147
  - Added support for @template property on Luca.View. Behaves the same as @bodyTemplate
@@ -151,7 +151,7 @@
151
151
  - View mixins use _initializer methods
152
152
  - FilterableView mixin for CollectionView classes
153
153
  - Added Rails Generator for Luca.Application skeleton. ( thanks @nick-desteffen )
154
- - Adds ability to pass a function reference as a component. The container will call the function, in
154
+ - Adds ability to pass a function reference as a component. The container will call the function, in
155
155
  the context of the container, and use the returned object as the component definition template
156
156
  - Adds a defaults property to containers. This will apply the values as defaults to each component.
157
157
  - Adds Luca.EventsExt an optional core extension which provides additional event binding sugar
@@ -160,20 +160,43 @@
160
160
  - bugfixes in CardView
161
161
 
162
162
  0.9.5
163
- - Luca.Model gets a 'read' method which will a getter function,
163
+ - Luca.Model gets a 'read' method which will a getter function,
164
164
  or get an attribute for the given property you are trying to 'read'
165
165
  - CollectionView is modifiable through several mixins:
166
166
  - Filterable
167
167
  - Paginatable
168
168
  - Loadmaskable
169
- - Introduces component definition helpers: extends,
170
- behavesAs, triggers, defaultsTo which allow for a more
169
+ - Introduces component definition helpers: extends,
170
+ behavesAs, triggers, defaultsTo which allow for a more
171
171
  "literate" component definiton style
172
172
  - View helpers moved into mixins:
173
173
  - StateModel
174
174
  - EnhancedProperties
175
175
  - CollectionEventBindings
176
- - ApplicationEventBindings
176
+ - ApplicationEventBindings
177
177
  - Changed syntax for @componentEvents configuration on Luca.core.Container.
178
- - now accepts role, name, or getter method
178
+ - now accepts role, name, or getter method
179
179
  - now accepts * for component, to bind to the same event on all components
180
+
181
+ 0.9.65
182
+ - Luca.core.Container components can now be configured with a @container property
183
+ which accepts any valid CSS selector so long as it is scoped within that container view's @$el.
184
+ Previously required an element with a specific ID which made it harder to build extendable components
185
+ with specific render targets
186
+
187
+ 0.9.66
188
+ - Luca.core.Container components can now be extended by subclasses by specifying an @extensions property.
189
+ @extensions work by applying the hash to the component in the same index'd position as that component
190
+ configuration in the superclass.
191
+ - Luca.components.CollectionView now has a @loadModels() method which resets the collection with the passed models.
192
+ - Added @componentMetaData() method which is going to replace the trickery done behind the scenes in Luca.extend
193
+ - Luca.config.autoApplyCssClassHierarchy if set to true, will add css class names to your luca components to make inheritance based styling easier.
194
+
195
+ 0.9.7
196
+ - Introduced publicInterface, publicConfiguration, privateInterface, and privateConfiguration as component registry methods.
197
+ These methods are intended to offer finer grain control over the component definition process for the purposes of building
198
+ our auto-generated documentation tool.
199
+ - Added Luca.concern support on Collection and Model
200
+ - Renaming 'mixin' and 'module' functionality to 'concern'
201
+ - Luca.concerns now follow the active support concern in spirit, with __included hooks, ClassMethods handling, etc
202
+ - Introducing an optional Concern for Luca.Model classes, called ModelPresenter.
@@ -1,6 +1,6 @@
1
1
  module Luca
2
2
  module Rails
3
- VERSION = "0.9.6"
3
+ VERSION = "0.9.7"
4
4
  end
5
5
  end
6
6
 
@@ -1,9 +1,9 @@
1
1
  describe 'The Collection View', ->
2
2
  beforeEach ->
3
3
  @collection = new Luca.Collection([
4
- id: 1, attr: "value_one"
4
+ id: 1, attr: "value_one", filter: "value"
5
5
  ,
6
- id: 2, attr: "value_two"
6
+ id: 2, attr: "value_two", filter: "value"
7
7
  ],
8
8
  model: Luca.Model)
9
9
 
@@ -12,9 +12,31 @@ describe 'The Collection View', ->
12
12
  itemClassName: "custom-class"
13
13
  itemProperty: 'attr'
14
14
  collection: @collection
15
+ filterable:
16
+ query:
17
+ filter: "value"
18
+ options:
19
+ sortBy: "filter"
15
20
 
16
21
  @view.render()
17
22
 
23
+ it "should provide access to the query", ->
24
+ expect( @view.getQuery() ).toBeDefined()
25
+
26
+ it "should provide access to the query options", ->
27
+ expect( @view.getQueryOptions() ).toBeDefined()
28
+
29
+ it "should combine filter and pagination in the options hash", ->
30
+ @view.setPage(5)
31
+ @view.applyFilter({filter:"value"},{sortBy:'filter'})
32
+
33
+ options = @view.getQueryOptions()
34
+ query = @view.getQuery()
35
+
36
+ expect( options.page ).toEqual 5
37
+ expect( options.sortBy ).toEqual 'filter'
38
+ expect( query.filter ).toEqual 'value'
39
+
18
40
  it "should render the attributes in the specified list elements", ->
19
41
  expect( @view.$html() ).toContain('value_one')
20
42
 
File without changes
@@ -0,0 +1,16 @@
1
+ describe 'The DOM Helpers module', ->
2
+ describe "The Wrapping Helper", ->
3
+ it "should accept a space delimited list", ->
4
+ v = new Luca.View(wrapperClass: "class-one class-two")
5
+ expect( v.$el.parent().is(".class-one.class-two") ).toEqual(true)
6
+
7
+ describe "Auto Assigning Class Names", ->
8
+ it "should apply the class of the component all the way up its hierarchy", ->
9
+ c = new Luca.core.Container()
10
+ expect( c.$el.is(".luca-container") ).toBeTruthy()
11
+ expect( c.$el.is(".luca-panel") ).toBeTruthy()
12
+
13
+ it "should leave out backbone and luca view classes", ->
14
+ c = new Luca.core.Container()
15
+ expect( c.$el.is(".luca-view") ).not.toBeTruthy()
16
+ expect( c.$el.is(".backbone-view") ).not.toBeTruthy()
@@ -0,0 +1,25 @@
1
+ describe 'The Filterable Plugin', ->
2
+ describe 'Through the CollectionView', ->
3
+ beforeEach ->
4
+ @collection = new Luca.Collection [{name:"name"},{name:"filterable"}]
5
+
6
+ @view = new Luca.components.TableView
7
+ collection:@collection
8
+ columns:[reader:"name"]
9
+
10
+ it 'should generate a Backbone.QueryCollection query payload', ->
11
+ expect( @view.getFilterState().toQuery() ).toBeDefined()
12
+
13
+ it "should have a toRemote method which merges params", ->
14
+ expect( @view.getFilterState().toRemote() ).toBeDefined()
15
+
16
+ it 'should apply filter values', ->
17
+ @view.applyFilter(filter:"value")
18
+ expect( @view.getFilterState().toQuery().filter ).toEqual('value')
19
+
20
+ it 'should generate a Backbone.QueryCollection options payload', ->
21
+ expect( @view.getFilterState().toOptions() ).toBeDefined()
22
+
23
+ it "should trigger a refresh event on filter change", ->
24
+ @view.applyFilter(filter:"value")
25
+ expect( @view ).toHaveTriggered("refresh")
@@ -0,0 +1,31 @@
1
+ describe 'The Presenter Mixin', ->
2
+ presenterModel = Luca.register("Luca.models.PresenterModel").extends("Luca.Model")
3
+ presenterModel.mixesIn("ModelPresenter")
4
+ presenterModel.defines
5
+ randomProperty: "chocolate"
6
+ fullName: ()->
7
+ @get("first_name") + ' ' + @get("last_name")
8
+ defaults:
9
+ first_name: "Jonathan"
10
+ last_name: "Soeder"
11
+
12
+ it "should respond to presentAs", ->
13
+ expect( Luca.models.PresenterModel::presentAs ).toBeDefined()
14
+
15
+ it "should define the presenter class methods on the model class", ->
16
+ expect( Luca.models.PresenterModel.registerPresenter ).toBeDefined()
17
+
18
+ it "should define the presenter class methods on the model class", ->
19
+ expect( Luca.models.PresenterModel.getPresenter ).toBeDefined()
20
+
21
+ it "should register a presenter format", ->
22
+ Luca.models.PresenterModel.registerPresenter "names", ["first_name", "last_name", "fullName"]
23
+ expect( Luca.models.PresenterModel.getPresenter("names") ).toBeDefined()
24
+
25
+ it "should present a model in the desired format", ->
26
+ model = new Luca.models.PresenterModel()
27
+ presented = model.presentAs('names')
28
+ expect( _.isObject(presented) ).toEqual true
29
+ expect( presented ).toBeDefined()
30
+ expect( _( presented ).keys()... ).toEqual "first_name", "last_name", "fullName"
31
+ expect( presented.fullName ).toEqual 'Jonathan Soeder'
File without changes
File without changes
@@ -0,0 +1,88 @@
1
+ describe 'The Concern System', ->
2
+
3
+ window.Luca ||= {}
4
+
5
+ Luca.concern.namespace 'Luca.test_concerns'
6
+
7
+ Luca.test_concerns =
8
+ CollectionMixin:
9
+ __initializer: ()->
10
+ @trigger "collection:mixin"
11
+ SecondMixin:
12
+ __included: ()->
13
+ window.secondMixinIncluded = true
14
+ __initializer: ()->
15
+ @trigger "second:mixin"
16
+ FirstMixin:
17
+ __initializer: ()->
18
+ @trigger "first:mixin"
19
+ __privateMethod: ()->
20
+ true
21
+ publicMethod: ()->
22
+ true
23
+
24
+ sampleView = Luca.register('Luca.components.FirstView')
25
+
26
+ sampleView.mixesIn 'FirstMixin'
27
+
28
+ sampleView.defines
29
+ sampleMethod: ()->
30
+ "sample"
31
+
32
+ secondView = Luca.register("Luca.components.SecondView")
33
+ secondView.extends 'Luca.components.FirstView'
34
+ secondView.mixesIn 'SecondMixin'
35
+ secondView.defines
36
+ version: 2
37
+
38
+ collection = Luca.register("Luca.components.MixinCollection")
39
+ collection.mixesIn "CollectionMixin"
40
+ collection.defines version: 2
41
+
42
+ model = Luca.register("Luca.components.MixinModel")
43
+ model.mixesIn "CollectionMixin"
44
+ model.defines version: 2
45
+
46
+ it "should work on models", ->
47
+ model = new Luca.components.MixinModel()
48
+ expect( model ).toHaveTriggered("collection:mixin")
49
+
50
+ it "should work on collections", ->
51
+ collection = new Luca.components.MixinCollection()
52
+ expect( collection ).toHaveTriggered("collection:mixin")
53
+
54
+ it "should work on views", ->
55
+ secondView = new Luca.components.SecondView
56
+ expect( secondView ).toHaveTriggered("second:mixin")
57
+
58
+ it "should omit methods prefixed with the double underscore", ->
59
+ sampleView = new Luca.components.FirstView
60
+ expect( sampleView.__privateMethod ).not.toBeDefined()
61
+
62
+
63
+ it "should extend the prototype with the concern definition", ->
64
+ sampleView = new Luca.components.FirstView
65
+ expect( sampleView.publicMethod ).toBeDefined()
66
+
67
+ it "should call the initializers up the prototype chain", ->
68
+ secondView = new Luca.components.SecondView
69
+ expect( secondView ).toHaveTriggered("first:mixin")
70
+ expect( secondView ).toHaveTriggered("second:mixin")
71
+
72
+ describe "Class Methods on the concern", ->
73
+ Luca.test_concerns.ExampleConcern =
74
+ instanceMethod: ()-> "instanceMethod"
75
+ classMethods:
76
+ classMethod: ()-> "classMethod"
77
+
78
+ v = Luca.register("Luca.components.ClassMethodView").mixesIn("ExampleConcern")
79
+
80
+ v.defines(version:1)
81
+
82
+ it "should distinguish between instance methods and class methods", ->
83
+ value = Luca.components.ClassMethodView::instanceMethod.call(@)
84
+ expect( value ).toEqual 'instanceMethod'
85
+
86
+ it "should distinguish between instance methods and class methods", ->
87
+ value = Luca.components.ClassMethodView.classMethod.call(@)
88
+ expect( value ).toEqual 'classMethod'
@@ -3,6 +3,13 @@ describe 'The Luca Container', ->
3
3
  c = @container = new Luca.core.Container
4
4
  defaults:
5
5
  defaultProperty: 'it_works'
6
+ extensions:[
7
+ extension: 1
8
+ ,
9
+ extension: 2
10
+ ,
11
+ extension: 3
12
+ ]
6
13
  components:[
7
14
  name: "component_one"
8
15
  ctype: "view"
@@ -47,6 +54,10 @@ describe 'The Luca Container', ->
47
54
  it "should create a getter function on the container", ->
48
55
  expect( @container.getOne().name ).toEqual 'component_one'
49
56
 
57
+ it "should apply extensions to the components", ->
58
+ expect( @container.getRoleOne().extension ).toEqual 1
59
+ expect( @container.getRoleTwo().extension ).toEqual 2
60
+
50
61
  it "should apply default properties to components", ->
51
62
  defaults = @container.selectByAttribute('defaultProperty','it_works')
52
63
  custom = @container.selectByAttribute('defaultProperty','oh_yeah')
@@ -85,31 +96,70 @@ describe 'The Luca Container', ->
85
96
  @container.eachComponent (c)-> c.spy()
86
97
  expect( Luca.cache("component_four").spy ).toHaveBeenCalled()
87
98
 
99
+ describe 'Component Inheritance and Customization', ->
100
+ it "should accept an array for extensions configuration and join on position/index", ->
101
+ container = new Luca.core.Container
102
+ extensions:[
103
+ undefined
104
+ ,
105
+ name: "custom_two"
106
+ ]
107
+ components:[
108
+ role: "component_one"
109
+ name: "component_one"
110
+ ,
111
+ role: "component_two"
112
+ name: "component_two"
113
+ ]
114
+
115
+ container.render()
116
+
117
+ expect( container.getComponentTwo().name ).toEqual "custom_two"
118
+
119
+ it "should accept an object for extensions configuration and join using role", ->
120
+ container = new Luca.core.Container
121
+ extensions:
122
+ component_one:
123
+ name: "custom_one"
124
+ components:[
125
+ role: "component_one"
126
+ name: "component_one"
127
+ ,
128
+ role: "component_two"
129
+ name: "component_two"
130
+ ]
131
+
132
+ container.render()
133
+
134
+ expect( container.getComponentOne().name ).toEqual "custom_one"
88
135
 
89
136
  describe 'Component Event Binding', ->
90
137
  beforeEach ->
91
138
  @container = new Luca.core.Container
92
139
  componentEvents:
93
- "component_alpha trigger:one" : "one"
140
+ "haha trigger:one" : "one"
94
141
  "alpha trigger:two" : "two"
95
142
  "getAlphaComponent trigger:three" : "three"
96
143
  "* trigger:four" : "four"
97
144
  "beta trigger:five" : "five"
98
145
 
99
146
  one: ()->
100
- @trigger "one"
147
+ @trigger "one"
101
148
 
102
149
  two: ()->
103
- @trigger "two"
150
+ @trigger "two"
104
151
 
105
152
  three: ()->
106
- @trigger "three"
153
+ @trigger "three"
107
154
 
108
155
  four: ()->
109
- @trigger "four"
156
+ @trigger "four"
110
157
 
111
158
  five: ()->
112
- @trigger "five"
159
+ @trigger "five"
160
+
161
+ afterRender: ()->
162
+ @getGamma().trigger("after:render:gamma")
113
163
 
114
164
  registerComponentEvents: ()->
115
165
  Luca.core.Container::registerComponentEvents.apply(@, arguments)
@@ -124,6 +174,10 @@ describe 'Component Event Binding', ->
124
174
  components:[
125
175
  name: "beta_view"
126
176
  role: "beta"
177
+ components:[
178
+ role: "gamma"
179
+ name: "haha"
180
+ ]
127
181
  ]
128
182
  ]
129
183
 
@@ -131,27 +185,35 @@ describe 'Component Event Binding', ->
131
185
 
132
186
  it "should give me all of the components", ->
133
187
  names = _( @container.allChildren() ).pluck('name')
134
- expect( names ).toEqual ['component_alpha','container_tester','beta_view']
188
+ expect( names ).toEqual ['component_alpha','container_tester','beta_view','haha']
135
189
 
136
190
  it "should drill down into nested components", ->
137
191
  expect( @container.getBeta ).toBeDefined()
138
192
  expect( @container.getBeta().name ).toEqual 'beta_view'
139
193
 
194
+ it "should observe the right rendering order", ->
195
+ expect( @container.getGamma() ).toHaveTriggered("after:render:gamma")
196
+
140
197
  it "should pick up events on nested components", ->
141
198
  @container.getBeta().trigger("trigger:five")
142
199
  expect( @container ).toHaveTriggered("five")
143
200
 
144
- it "should define a role based getter", ->
201
+ it "should recursively define role based getters", ->
145
202
  expect( @container.getAlpha ).toBeDefined()
203
+ expect( @container.getBeta ).toBeDefined()
204
+ expect( @container.getGamma ).toBeDefined()
146
205
 
147
206
  it "should define a getter", ->
148
207
  expect( @container.getAlphaComponent ).toBeDefined()
149
208
 
150
- it "should find the component by its role", ->
151
- expect( @container.findComponentByRole("alpha") ).toBeDefined()
209
+ it "should find a nested component by name", ->
210
+ expect( @container.findComponentByName('haha') ).toBeDefined()
152
211
 
153
212
  it "should find the component by its name", ->
154
- expect( @container.findComponentByName('component_alpha') ).toBeDefined()
213
+ expect( @container.findComponentByName("beta_view") ).toBeDefined()
214
+
215
+ it "should find the component by its role", ->
216
+ expect( @container.findComponentByRole("alpha") ).toBeDefined()
155
217
 
156
218
  it "should find the component by its getter", ->
157
219
  expect( @container.findComponentByGetter('getAlphaComponent') ).toBeDefined()
@@ -161,7 +223,7 @@ describe 'Component Event Binding', ->
161
223
  expect( @container ).toHaveTriggered("four")
162
224
 
163
225
  it "should accept component events with a component name", ->
164
- @container.getAlphaComponent().trigger "trigger:one"
226
+ @container.getGamma().trigger "trigger:one"
165
227
  expect(@container).toHaveTriggered("one")
166
228
 
167
229
  it "should accept component events with a component role", ->
@@ -50,13 +50,14 @@ describe "Luca.Model with computed attribute", ->
50
50
  expect(model.get("fullName")).toEqual('Nickolay Schwarz')
51
51
 
52
52
 
53
- describe 'The Read Method', ->
54
53
 
54
+ describe 'The Read Method', ->
55
55
  ModelClass = Luca.Model.extend
56
56
  defaults:
57
57
  attribute: "attribute"
58
58
  reader: ()->
59
59
  "reader"
60
+ property: true
60
61
 
61
62
  it "should read an attribute", ->
62
63
  model = new ModelClass()
@@ -66,3 +67,7 @@ describe 'The Read Method', ->
66
67
  model = new ModelClass()
67
68
  expect( model.read('attribute') ).toEqual "attribute"
68
69
  expect( model.read('reader') ).toEqual 'reader'
70
+
71
+ it "should read model object attributes as a fallback", ->
72
+ model = new ModelClass()
73
+ expect( model.read('property') ).toEqual true
@@ -10,10 +10,4 @@ describe 'The Component Definition System', ->
10
10
  Luca.register("Luca.components.SampleComponentDefinition").defines(version: 1)
11
11
  expect( Luca.parentClasses(Luca.components.SampleComponentDefinition) ).toContain 'Luca.View'
12
12
 
13
- it "should track the parent classes", ->
14
- Luca.register("Luca.components.SampleComponentDefinition").defines(version: 1)
15
- expect( Luca.parentClasses(Luca.components.SampleComponentDefinition) ).toEqual ['Luca.View','Backbone.View']
16
-
17
- xit "should defer component extension until dependencies are defined", ->
18
-
19
13
 
@@ -0,0 +1,24 @@
1
+ describe 'The Luca Utilities', ->
2
+ describe "Converting from component class to css class", ->
3
+ it "should produce a css class from the component class name", ->
4
+ component = "Luca.core.Container"
5
+ cssClass = Luca.util.toCssClass(component)
6
+ expect( cssClass ).toEqual 'luca-core-container'
7
+
8
+ it "should produce a css class from the component class name", ->
9
+ component = "Luca.components.MultiCollectionView"
10
+ cssClass = Luca.util.toCssClass(component)
11
+ expect( cssClass ).toEqual 'luca-components-multi-collection-view'
12
+
13
+ it "should produce a css class from the component class name", ->
14
+ component = "Luca.View"
15
+ cssClass = Luca.util.toCssClass(component)
16
+ expect( cssClass ).toEqual 'luca-view'
17
+
18
+ it "should exclude parts", ->
19
+ component = "Luca.components.MultiCollectionView"
20
+ cssClass = Luca.util.toCssClass(component, 'components')
21
+ expect( cssClass ).toEqual "luca-multi-collection-view"
22
+
23
+
24
+