glia 0.1.0
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.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/.rakeTasks +7 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +236 -0
- data/Rakefile +2 -0
- data/glia.gemspec +23 -0
- data/lib/glia/cell.rb +15 -0
- data/lib/glia/errors.rb +6 -0
- data/lib/glia/layout.rb +34 -0
- data/lib/glia/update_builder.rb +76 -0
- data/lib/glia/update_registry.rb +17 -0
- data/lib/glia/version.rb +3 -0
- data/lib/glia/view_factory.rb +26 -0
- data/lib/glia.rb +18 -0
- data/test/fixtures/layout/default.rb +32 -0
- data/test/fixtures/layout.rb +1 -0
- data/test/fixtures/view/core/html.rb +8 -0
- data/test/fixtures/view/list.rb +7 -0
- data/test/fixtures/view/template.rb +17 -0
- data/test/fixtures/view.rb +3 -0
- data/test/test_helper.rb +11 -0
- data/test/unit/layout_test.rb +32 -0
- data/test/unit/update_builder_test.rb +53 -0
- data/test/unit/view_factory_test.rb +23 -0
- metadata +122 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8f3643b91dabc177197be3c240ff6de7c21522c0
|
4
|
+
data.tar.gz: 3f493ca6458e66cf8f39735f7f2e81b8f960a0e6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ddfebae6ff8ffdb40e9cdfd0cb877714e4dfa68b62668f80b36bc7cf0c9997a7c216e0359dbec91eb98a7098d5239b12538ee7ebcc8afbab4a3c7d1db06b6011
|
7
|
+
data.tar.gz: 45006a08c0f57dfeec98722b6b81ce960057a032516952bb0037d8befcc55098c24d1305f2727d1948a032fe9f39b1d8613afdacc62676ebd2fb41c5aae31a75
|
data/.gitignore
ADDED
data/.rakeTasks
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<Settings><!--This file was automatically generated by Ruby plugin.
|
3
|
+
You are allowed to:
|
4
|
+
1. Remove rake task
|
5
|
+
2. Add existing rake tasks
|
6
|
+
To add existing rake tasks automatically delete this file and reload the project.
|
7
|
+
--><RakeGroup description="" fullCmd="" taksId="rake"><RakeTask description="Build glia-0.0.1.gem into the pkg directory" fullCmd="build" taksId="build" /><RakeTask description="Build and install glia-0.0.1.gem into system gems" fullCmd="install" taksId="install" /><RakeTask description="Create tag v0.0.1 and build and push glia-0.0.1.gem to Rubygems" fullCmd="release" taksId="release" /></RakeGroup></Settings>
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Dane Lowe
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,236 @@
|
|
1
|
+
# Glia
|
2
|
+
|
3
|
+
As your app grows, you may find that a lot of logic is necessary in your views.
|
4
|
+
Implementing a proper view layer, such as [Cells](https://github.com/apotonick/cells),
|
5
|
+
will help to reduce complexity by encapsulating this logic into classes for specific parts of the page.
|
6
|
+
|
7
|
+
But what happens when you need somewhere to manage the logic determining what cells go where and on what page?
|
8
|
+
This is where Glia comes in handy, it provides an additional `layout` layer to manage your views.
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
Add this line to your application's Gemfile:
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
gem 'glia'
|
16
|
+
```
|
17
|
+
|
18
|
+
And then execute:
|
19
|
+
|
20
|
+
$ bundle
|
21
|
+
|
22
|
+
Or install it yourself as:
|
23
|
+
|
24
|
+
$ gem install glia
|
25
|
+
|
26
|
+
## Usage
|
27
|
+
|
28
|
+
### Cells
|
29
|
+
A Cell is a view object that renders a certain part of the page.
|
30
|
+
|
31
|
+
**Glia does not provide an implementation of cells, but expects that you have this concept as part of your project.**
|
32
|
+
|
33
|
+
You can use a gem such as [Cells](https://github.com/apotonick/cells), to provide this interface.
|
34
|
+
|
35
|
+
Glia provides a mixin, `Glia::Cell` that you should include in your cells to provide methods that help with things
|
36
|
+
such as setting/getting child cells, and accessing the layout layer.
|
37
|
+
|
38
|
+
### Layout files
|
39
|
+
Layout files are written with a DSL that is designed to help describe the layout of your pages. e.g.
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
# layout/frontend/default.rb
|
43
|
+
Glia.area(:frontend) do
|
44
|
+
handle :default do
|
45
|
+
cell name: :root, class: :'core/html', template_name: 'root', missing_accessor: 'ignore_me' do
|
46
|
+
cell name: :header, class: :template, template_name: 'header'
|
47
|
+
end
|
48
|
+
end
|
49
|
+
handle :cake_view do
|
50
|
+
reference name: :root do
|
51
|
+
cell name: :details, class: Fixtures::View::Template, template_name: 'cake_details', position: :content do
|
52
|
+
cell name: :specifications, class: :list do
|
53
|
+
cell name: :cake_specs, class: 'Template', template_name: 'cake/specs'
|
54
|
+
cell name: :cake_ingredients, class: :template, template_name: 'cake/ingredients'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
handle :pavlova_view do
|
60
|
+
reference name: :specifications do
|
61
|
+
remove name: :cake_specs
|
62
|
+
end
|
63
|
+
reference name: :cake_ingredients, template_name: 'cake/pavlova_ingredients' do
|
64
|
+
action name: :add_ingredient, args: ['Eggs', '6 Large']
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
```
|
69
|
+
|
70
|
+
#### Handle
|
71
|
+
|
72
|
+
Handles are key tool for customising your layout per page.
|
73
|
+
Each page in your app will have a set of handles, which consist of an array of symbols. e.g.
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
[:default, :cake_view, :pavlova_view]
|
77
|
+
```
|
78
|
+
|
79
|
+
It is often a good idea to have the handles automatically generated from the controller,
|
80
|
+
including a default handle, one for the controller name, and another for the controller#action name.
|
81
|
+
You can also have your controller add custom handles depending on the request, or the type of item being viewed. e.g.
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
[:default, :quotes, :quotes_show, :quotes_show_AJAX, :quote_show_TYPE_PLUMBING]
|
85
|
+
```
|
86
|
+
|
87
|
+
If your project has a concept of modules (that encapsulates a feature and contains controllers), then it would also be
|
88
|
+
a very good idea to include the module name in your handles. e.g.
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
[:default, :sales_quotes, :sales_quotes_show]
|
92
|
+
```
|
93
|
+
|
94
|
+
**The order of the set of handles is important.** Glia will start at the first handle (e.g. `:default`) when building
|
95
|
+
the layout.
|
96
|
+
Each successive handle will modify the layout generated from the previous handle.
|
97
|
+
In the DSL example above, if our handles were `[:default, :cake_view, :pavlova_view]`, then the template_name for
|
98
|
+
the `cake_ingredients` cell will be 'cake/pavlova_ingredients', and we won't have a `:cake_specs` cell on the page.
|
99
|
+
|
100
|
+
Using this system, we can have considerable flexibility in the layout based on the factors that we use to determine the
|
101
|
+
handles. For example, we can add or remove menu items from a navigation cell if the customer is logged in,
|
102
|
+
or if we are on the customer account page. We can add or remove certain cells on the page based on the type of product
|
103
|
+
that we are viewing.
|
104
|
+
|
105
|
+
Generating the handles for a request/action and passing them to the layout during rendering is decribed in further
|
106
|
+
detail in the *Integration* section.
|
107
|
+
|
108
|
+
All layout methods are contained within a handle, and as such all other methods must appear inside a handle block.
|
109
|
+
|
110
|
+
#### Cell
|
111
|
+
|
112
|
+
The `cell` method places a cell inside the layout.
|
113
|
+
The layout starts with a single cell, which by convention is named `:root`.
|
114
|
+
All other cells on the page are descendants of the root cell, and most likely will be rendered as part of rendering the
|
115
|
+
root cell, being contained in its output.
|
116
|
+
|
117
|
+
* `name` is the name of the cell in the layout. Each cell must have its own unique name within the layout
|
118
|
+
* `class` is a code that the layout system uses to figure out what class to instantiate when building the cell.
|
119
|
+
This can either be:
|
120
|
+
* A String representing the class name, either fully qualified or from the view_namespace (see **Integration**)
|
121
|
+
* A Symbol Representing the class name from the view_namespace, separated by '/' for each sub-namespace.
|
122
|
+
* A Class
|
123
|
+
* `position` This is a code that should be unique within the parent cell. If omitted, will default to the same value as
|
124
|
+
`name`. This code is used to control where the cell is rendered within the parent cell, using the `cell`
|
125
|
+
method. For example, the `'cake_details'` template file might have a call to `cell(:specifications).render` in a
|
126
|
+
specific place to render that specific child cell.
|
127
|
+
* Any other parameters passed to `cell` will be passed through to the cell's constructor.
|
128
|
+
* Anything in the block will operate on this cell. E.g. calling cell withing the block will create a child cell.
|
129
|
+
|
130
|
+
#### Reference
|
131
|
+
|
132
|
+
The `reference` method refers to a cell that has been added in a previous handle. Anything parameter will overwrite the
|
133
|
+
same parameter defined in a previous handle. Any contents of the block will operate on the previously defined cell.
|
134
|
+
|
135
|
+
The technical difference from the cell method is that instead of requiring the `class` parameter, it disallows it,
|
136
|
+
and a reference without a matching cell would be ignored rather than creating a cell in the layout.
|
137
|
+
|
138
|
+
#### Action
|
139
|
+
|
140
|
+
This method will run the specified method (with the given arguments) on the cell immediately after it is initialized.
|
141
|
+
* `name` The name of the method
|
142
|
+
* `args` An array of arguments that will be passed to the method.
|
143
|
+
|
144
|
+
|
145
|
+
### Areas
|
146
|
+
|
147
|
+
An 'area' is a distinct layout that is completely separate from another area.
|
148
|
+
For example many apps would have a `:frontend` area, and a `:backend` area.
|
149
|
+
|
150
|
+
If you app code is organised into modules, you may wish to keep a layout file in each module.
|
151
|
+
This way, the layout files can each place cells related to their own modules on any page of the app.
|
152
|
+
|
153
|
+
Just wrap the DSL with `Glia.area(:area_name) do .. end`,
|
154
|
+
then make sure the layout files are required as part of your app's bootstrap process.
|
155
|
+
|
156
|
+
```ruby
|
157
|
+
Glia.area(:frontend) do
|
158
|
+
handle :pavlova_view do
|
159
|
+
reference name: :specifications do
|
160
|
+
remove name: :cake_specs
|
161
|
+
end
|
162
|
+
reference name: :cake_ingredients, template_name: 'cake/pavlova_ingredients' do
|
163
|
+
action name: :add_ingredient, args: ['Eggs', '6 Large']
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
```
|
168
|
+
|
169
|
+
### Integration
|
170
|
+
|
171
|
+
#### Generate the handles
|
172
|
+
|
173
|
+
The handles will be generated in the controller based on the request/loaded objects/controller. Examples to come.
|
174
|
+
|
175
|
+
#### Configure the layout
|
176
|
+
|
177
|
+
If you wish to use class codes in place of classes, Tell it what namespace to use when finding classes for a class code.
|
178
|
+
|
179
|
+
```ruby
|
180
|
+
Glia::Layout.view_namespace = Fixtures::View
|
181
|
+
```
|
182
|
+
|
183
|
+
#### Create a layout
|
184
|
+
|
185
|
+
Pick an 'area' to render, e.g. `:frontend` or `:admin`, and pass this into the layout method along with the handles.
|
186
|
+
|
187
|
+
````ruby
|
188
|
+
layout = Glia.layout(:frontend, [:default, :cake_view, :pavlova_view])
|
189
|
+
```
|
190
|
+
|
191
|
+
This returns an instance of Glia::Layout
|
192
|
+
|
193
|
+
### Render the layout.
|
194
|
+
|
195
|
+
Get the `:root` cell from the layout, and render it. The `render` method is provided by your view layer library/gem.
|
196
|
+
Substitute the method name that you have.
|
197
|
+
|
198
|
+
```ruby
|
199
|
+
layout.cell(:root).render
|
200
|
+
```
|
201
|
+
|
202
|
+
That is all. Your root cell's rendering process should be such that the child cells are picked out and rendered,
|
203
|
+
and those child cells pick out and render their child cells, and so on until the whole layout tree is rendered.
|
204
|
+
|
205
|
+
## Suggestions
|
206
|
+
|
207
|
+
### Suggested Cell Types
|
208
|
+
|
209
|
+
* `Template` A generic cell that has a `template_name` and a data passed into its constructor in key/value pairs.
|
210
|
+
It would render the template, using the data as locals.
|
211
|
+
* `List` A generic cell that has no template, but instead renders all child cells
|
212
|
+
(DSL to control order of child cells to come soon).
|
213
|
+
These can be very handy for providing areas such as sidebars, where any number of cells can be added or removed
|
214
|
+
without having to have a `cell(:name).render` helper called for each specific child cell
|
215
|
+
* `Html::Head` A cell with specific methods for including asset tags etc.
|
216
|
+
* Specific classes for cells that have their own logic. E.g. `Product::Price`, `Category::List`
|
217
|
+
|
218
|
+
### Getting data to cells
|
219
|
+
|
220
|
+
Try one or more of these options:
|
221
|
+
|
222
|
+
* Pass the data as locals to each cell or child cell as you render it.
|
223
|
+
* Create a registry (using e.g. [RequestStore](https://github.com/steveklabnik/request_store)), which the controller can
|
224
|
+
pass data to, and the cells can read data from.
|
225
|
+
* If more flexibility is required, the controller can pull a specific cell from the layout, and call a method on it.
|
226
|
+
|
227
|
+
## Notes
|
228
|
+
* When the DSL is parsed, the result is a simple hash of values that describes the layout.
|
229
|
+
|
230
|
+
## Contributing
|
231
|
+
|
232
|
+
1. Fork it ( https://github.com/danelowe/glia/fork )
|
233
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
234
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
235
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
236
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/glia.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'glia/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "glia"
|
8
|
+
spec.version = Glia::VERSION
|
9
|
+
spec.authors = ["Dane Lowe"]
|
10
|
+
spec.email = ["dane.r.lowe@gmail.com"]
|
11
|
+
spec.summary = %q{Manage App Layouts.}
|
12
|
+
spec.homepage = "https://github.com/danelowe/glia"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0")
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
21
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
22
|
+
spec.add_development_dependency 'minitest', '~> 5.0'
|
23
|
+
end
|
data/lib/glia/cell.rb
ADDED
data/lib/glia/errors.rb
ADDED
data/lib/glia/layout.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
module Glia
|
2
|
+
|
3
|
+
class Layout
|
4
|
+
attr_reader :handles, :data, :update, :cells
|
5
|
+
singleton_class.class_eval do
|
6
|
+
attr_accessor :layout_dir, :view_namespace
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(area, handles)
|
10
|
+
@update = UpdateRegistry.area(area)
|
11
|
+
@cells = {}
|
12
|
+
@handles = handles
|
13
|
+
@data = @update.merge(@handles)
|
14
|
+
end
|
15
|
+
|
16
|
+
def cell(name)
|
17
|
+
if @cells[name].nil?
|
18
|
+
definition = @data[name]
|
19
|
+
code = definition.delete(:class)
|
20
|
+
actions = definition.delete(:actions)
|
21
|
+
children = definition.delete(:children)
|
22
|
+
@cells[name] = view_factory.build(code, definition, actions)
|
23
|
+
children.each{|p, n| @cells[name].children[p] = cell(n)} unless children.nil?
|
24
|
+
end
|
25
|
+
@cells[name]
|
26
|
+
end
|
27
|
+
|
28
|
+
def view_factory
|
29
|
+
@view_factory ||= ViewFactory.new(self.class.view_namespace)
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module Glia
|
2
|
+
|
3
|
+
class UpdateBuilder
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@data = {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def handle(key, &blk)
|
10
|
+
begin
|
11
|
+
@current_scope = @data[key] ||= {}
|
12
|
+
@current_cell = nil
|
13
|
+
instance_eval &blk
|
14
|
+
ensure
|
15
|
+
@current_scope = nil
|
16
|
+
@current_cell = nil
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def cell(definition, &blk)
|
21
|
+
raise Glia::Errors::SyntaxError, 'cell must have a class' if definition[:class].nil?
|
22
|
+
_cell(definition, &blk)
|
23
|
+
end
|
24
|
+
|
25
|
+
def remove(definition)
|
26
|
+
@current_scope[definition.delete(:name)] = nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def reference(definition, &blk)
|
30
|
+
raise Glia::Errors::SyntaxError, 'Reference cannot have a class' unless definition[:class].nil?
|
31
|
+
_cell(definition, &blk)
|
32
|
+
end
|
33
|
+
|
34
|
+
def action(definition)
|
35
|
+
raise Glia::Errors::SyntaxError, 'Action cannot be used outside of cell' if @current_cell.nil?
|
36
|
+
@current_cell[:actions] ||= []
|
37
|
+
@current_cell[:actions] << definition
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_h
|
41
|
+
@data
|
42
|
+
end
|
43
|
+
|
44
|
+
def merge(handles)
|
45
|
+
_data = {}
|
46
|
+
merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 }
|
47
|
+
handles.each{|h| _data = _data.merge(@data[h].clone, &merger) unless @data[h].nil?}
|
48
|
+
_data.delete_if{|k, v| v.nil? || v[:class].nil?}.each_with_object({}) do |(name, definition), hash|
|
49
|
+
d = definition.clone
|
50
|
+
d[:children].delete_if{|position, n| _data[n].nil?}
|
51
|
+
d.delete(:children) if d[:children].empty?
|
52
|
+
hash[name] = d
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def _cell(definition, &blk)
|
59
|
+
raise Glia::Errors::SyntaxError, 'cell cannot be used outside of handle' if @current_scope.nil?
|
60
|
+
begin
|
61
|
+
name = definition.delete(:name)
|
62
|
+
position = definition.delete(:position) || name
|
63
|
+
old_cell = @current_cell
|
64
|
+
@current_cell = @current_scope[name] = {children: {}}.merge(definition)
|
65
|
+
unless old_cell.nil?
|
66
|
+
old_cell[:children][position] = name
|
67
|
+
end
|
68
|
+
instance_eval &blk unless blk.nil?
|
69
|
+
ensure
|
70
|
+
@current_cell = old_cell
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Glia
|
2
|
+
class UpdateRegistry
|
3
|
+
class << self
|
4
|
+
def area(code, &blk)
|
5
|
+
#@todo UpdateRegistry can load update_data from cache and instantiate new UpdateBuilder directly with cached data.
|
6
|
+
@updates ||= {}
|
7
|
+
update = @updates[code] ||= UpdateBuilder.new
|
8
|
+
|
9
|
+
if block_given?
|
10
|
+
update.instance_eval(&blk)
|
11
|
+
end
|
12
|
+
|
13
|
+
update
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/glia/version.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
module Glia
|
2
|
+
class ViewFactory
|
3
|
+
def initialize(namespace)
|
4
|
+
@namespace = namespace || Object
|
5
|
+
end
|
6
|
+
|
7
|
+
def build(code, definition = {}, actions = [])
|
8
|
+
object = find_class(code).new(definition)
|
9
|
+
actions.each do |action|
|
10
|
+
object.send(action[:name], *action[:args])
|
11
|
+
end unless actions.nil?
|
12
|
+
object
|
13
|
+
end
|
14
|
+
|
15
|
+
def find_class(code)
|
16
|
+
if code.is_a? Symbol
|
17
|
+
parts = code.to_s.split('/').map{ |str| str.split('_').map {|w| w.capitalize}.join }
|
18
|
+
parts.inject(@namespace){|namespace, part| namespace.const_get(part)}
|
19
|
+
elsif code.is_a? String
|
20
|
+
@namespace.const_get(code)
|
21
|
+
else
|
22
|
+
code
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/glia.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require "glia/version"
|
2
|
+
require "glia/cell"
|
3
|
+
require "glia/errors"
|
4
|
+
require "glia/layout"
|
5
|
+
require "glia/update_builder"
|
6
|
+
require "glia/update_registry"
|
7
|
+
require "glia/view_factory"
|
8
|
+
|
9
|
+
module Glia
|
10
|
+
# Your code goes here...
|
11
|
+
def self.area(code, &blk)
|
12
|
+
UpdateRegistry.area(code, &blk)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.layout(area, handles)
|
16
|
+
Layout.new(area, handles)
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
Glia.area(:frontend) do
|
2
|
+
|
3
|
+
handle :default do
|
4
|
+
cell name: :root, class: :'core/html', template_name: 'root', missing_accessor: 'ignore_me' do
|
5
|
+
cell name: :header, class: :template, template_name: 'header'
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
handle :cake_view do
|
10
|
+
reference name: :root do
|
11
|
+
cell name: :details, class: Fixtures::View::Template, template_name: 'cake_details', position: :content do
|
12
|
+
cell name: :specifications, class: :list do
|
13
|
+
cell name: :cake_specs, class: 'Fixtures::View::Template', template_name: 'cake/specs'
|
14
|
+
cell name: :cake_ingredients, class: 'Template', template_name: 'cake/ingredients'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
reference name: :non_existent, template: 'missing' do
|
19
|
+
cell name: :non_existent_child, class: :template
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
handle :pavlova_view do
|
24
|
+
reference name: :specifications do
|
25
|
+
remove name: :cake_specs
|
26
|
+
end
|
27
|
+
reference name: :cake_ingredients, template_name: 'cake/pavlova_ingredients' do
|
28
|
+
action name: :add_ingredient, args: ['Eggs', '6 Large']
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
Dir[File.expand_path('../layout/**/*.rb', __FILE__)].each {|f| require f}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Fixtures
|
2
|
+
module View
|
3
|
+
class Template
|
4
|
+
include Glia::Cell
|
5
|
+
attr_reader :template_name, :ingredients
|
6
|
+
|
7
|
+
def initialize(config)
|
8
|
+
@template_name = config[:template_name]
|
9
|
+
@ingredients = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def add_ingredient(name, qty)
|
13
|
+
@ingredients << "#{name} : #{qty}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
class Glia::Layout::Test < UnitTest
|
3
|
+
describe Glia::Layout do
|
4
|
+
|
5
|
+
Glia::Layout.view_namespace = Fixtures::View
|
6
|
+
let(:layout){ Glia.layout(:frontend, [:default, :cake_view, :pavlova_view]) }
|
7
|
+
|
8
|
+
def test_update
|
9
|
+
assert_equal :'core/html', layout.update.to_h[:default][:root][:class]
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_data
|
13
|
+
assert_equal :'core/html', layout.data[:root][:class]
|
14
|
+
assert_nil layout.data[:non_existent]
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_cell
|
18
|
+
root = layout.cell(:root)
|
19
|
+
assert_instance_of Fixtures::View::Core::Html, root
|
20
|
+
assert_equal 'root', root.template_name
|
21
|
+
assert_operator root.children.count, :>=, 1
|
22
|
+
child = root.cell(:content)
|
23
|
+
assert_equal layout.cell(:details), child
|
24
|
+
assert_instance_of Fixtures::View::Template, child
|
25
|
+
assert_equal 'cake_details', child.template_name
|
26
|
+
ingredients = layout.cell(:cake_ingredients)
|
27
|
+
assert_instance_of Fixtures::View::Template, ingredients
|
28
|
+
assert_equal 'cake/pavlova_ingredients', ingredients.template_name
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
class Glia::UpdateBuilder::Test < UnitTest
|
3
|
+
describe Glia::UpdateBuilder do
|
4
|
+
let(:builder) { Glia::UpdateBuilder.new }
|
5
|
+
|
6
|
+
def test_cell
|
7
|
+
builder.handle :test do
|
8
|
+
cell name: :root, class: :html, template_name: 'root' do
|
9
|
+
action name: :compile, args: ['javascript', 'css']
|
10
|
+
cell name: :header, class: :template, template_name: 'header'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
expected_output = {
|
14
|
+
test: {
|
15
|
+
root: {class: :html, template_name: 'root',
|
16
|
+
children: {header: :header}, actions: [{name: :compile, args: ['javascript', 'css']}]},
|
17
|
+
header: {class: :template, template_name: 'header', children: {}}
|
18
|
+
}
|
19
|
+
}
|
20
|
+
assert_equal expected_output, builder.to_h
|
21
|
+
assert_raises Glia::Errors::SyntaxError do
|
22
|
+
builder.cell name: :header, class: :template, template_name: 'header'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_merge
|
27
|
+
builder.handle :default do
|
28
|
+
cell name: :root, class: :html, template_name: 'root' do
|
29
|
+
action name: :compile, args: ['javascript', 'css']
|
30
|
+
cell name: :header, class: :template, template_name: 'header'
|
31
|
+
cell name: :footer, class: :template, template_name: 'footer'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
builder.handle :test do
|
35
|
+
remove name: :header
|
36
|
+
reference name: :footer, template_name: 'new_footer' do
|
37
|
+
cell name: :copyright, class: :template, template_name: 'copyright', position: :footer_bottom
|
38
|
+
end
|
39
|
+
end
|
40
|
+
expected_output = {
|
41
|
+
root: {
|
42
|
+
class: :html,
|
43
|
+
template_name: 'root',
|
44
|
+
children: {footer: :footer},
|
45
|
+
actions: [{name: :compile, args: ['javascript', 'css']}]
|
46
|
+
},
|
47
|
+
footer: {class: :template, template_name: 'new_footer', children: {footer_bottom: :copyright}},
|
48
|
+
copyright: {class: :template, template_name: 'copyright'}
|
49
|
+
}
|
50
|
+
assert_equal expected_output, builder.merge([:default, :test])
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
class Glia::ViewFactory::Test < UnitTest
|
3
|
+
describe Glia::ViewFactory do
|
4
|
+
let(:factory) { Glia::ViewFactory.new(Fixtures::View) }
|
5
|
+
|
6
|
+
def test_find_class
|
7
|
+
assert_equal Fixtures::View::Template, factory.find_class(:template)
|
8
|
+
assert_equal Fixtures::View::Core::Html, factory.find_class(:'core/html')
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_build
|
12
|
+
cell = factory.build(
|
13
|
+
:template,
|
14
|
+
{template_name: 'my_template'},
|
15
|
+
[{name: :add_ingredient, args: ['Eggs', '6 Large']}]
|
16
|
+
)
|
17
|
+
assert_instance_of Fixtures::View::Template, cell
|
18
|
+
assert_equal 'my_template', cell.template_name
|
19
|
+
assert_equal 'Eggs : 6 Large', cell.ingredients.first
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: glia
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Dane Lowe
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-08-02 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.7'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '5.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '5.0'
|
55
|
+
description:
|
56
|
+
email:
|
57
|
+
- dane.r.lowe@gmail.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- ".gitignore"
|
63
|
+
- ".rakeTasks"
|
64
|
+
- Gemfile
|
65
|
+
- LICENSE.txt
|
66
|
+
- README.md
|
67
|
+
- Rakefile
|
68
|
+
- glia.gemspec
|
69
|
+
- lib/glia.rb
|
70
|
+
- lib/glia/cell.rb
|
71
|
+
- lib/glia/errors.rb
|
72
|
+
- lib/glia/layout.rb
|
73
|
+
- lib/glia/update_builder.rb
|
74
|
+
- lib/glia/update_registry.rb
|
75
|
+
- lib/glia/version.rb
|
76
|
+
- lib/glia/view_factory.rb
|
77
|
+
- test/fixtures/layout.rb
|
78
|
+
- test/fixtures/layout/default.rb
|
79
|
+
- test/fixtures/view.rb
|
80
|
+
- test/fixtures/view/core/html.rb
|
81
|
+
- test/fixtures/view/list.rb
|
82
|
+
- test/fixtures/view/template.rb
|
83
|
+
- test/test_helper.rb
|
84
|
+
- test/unit/layout_test.rb
|
85
|
+
- test/unit/update_builder_test.rb
|
86
|
+
- test/unit/view_factory_test.rb
|
87
|
+
homepage: https://github.com/danelowe/glia
|
88
|
+
licenses:
|
89
|
+
- MIT
|
90
|
+
metadata: {}
|
91
|
+
post_install_message:
|
92
|
+
rdoc_options: []
|
93
|
+
require_paths:
|
94
|
+
- lib
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
requirements: []
|
106
|
+
rubyforge_project:
|
107
|
+
rubygems_version: 2.4.5
|
108
|
+
signing_key:
|
109
|
+
specification_version: 4
|
110
|
+
summary: Manage App Layouts.
|
111
|
+
test_files:
|
112
|
+
- test/fixtures/layout.rb
|
113
|
+
- test/fixtures/layout/default.rb
|
114
|
+
- test/fixtures/view.rb
|
115
|
+
- test/fixtures/view/core/html.rb
|
116
|
+
- test/fixtures/view/list.rb
|
117
|
+
- test/fixtures/view/template.rb
|
118
|
+
- test/test_helper.rb
|
119
|
+
- test/unit/layout_test.rb
|
120
|
+
- test/unit/update_builder_test.rb
|
121
|
+
- test/unit/view_factory_test.rb
|
122
|
+
has_rdoc:
|