xhive 1.0.9.pre → 1.2.0.pre

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -34,22 +34,28 @@ Run bundle install
34
34
 
35
35
  Run xhive migrations
36
36
 
37
- ```
37
+ ```bash
38
38
  rake xhive:install:migrations
39
39
  rake db:migrate
40
40
  ```
41
41
 
42
42
  Include the xhive javascript in your head tag.
43
43
 
44
- `<%= javascript_include_tag "xhive/application" %>`
44
+ ```erb
45
+ <%= javascript_include_tag "xhive/application" %>
46
+ ```
45
47
 
46
48
  Include the custom stylesheets in your head tag.
47
49
 
48
- `<%= include_custom_stylesheets %>`
50
+ ```erb
51
+ <%= include_custom_stylesheets %>
52
+ ```
49
53
 
50
54
  Include the widgets loader just before your \<\\body\> tag.
51
55
 
52
- `<%= initialize_widgets_loader %>`
56
+ ```erb
57
+ <%= initialize_widgets_loader %>
58
+ ```
53
59
 
54
60
  # Usage
55
61
 
@@ -59,29 +65,33 @@ Include the widgets loader just before your \<\\body\> tag.
59
65
 
60
66
  Let's say you have a Posts controller and you want to access the show action as a widget.
61
67
 
62
- ```
63
- app/controller/posts_controller.rb
68
+ `app/controller/posts_controller.rb`
64
69
 
70
+ ```ruby
65
71
  class PostsController < ApplicationController
66
72
  def show
67
73
  @post = Post.find(params[:id])
68
74
  end
69
75
  end
76
+ ```
70
77
 
71
- app/views/posts/show.html.erb
78
+ `app/views/posts/show.html.erb`
72
79
 
80
+ ```erb
73
81
  <h1><%= @post.title %></h1>
74
82
 
75
83
  <p><%= @post.body %></p>
84
+ ```
76
85
 
77
- config/routes.rb
86
+ `config/routes.rb`
78
87
 
88
+ ```ruby
79
89
  resources :posts, :only => [:show]
80
-
81
90
  ```
91
+
82
92
  Just tell xhive to *widgify* your action:
83
93
 
84
- ```
94
+ ```ruby
85
95
  class PostsController < ApplicationController
86
96
  widgify :show
87
97
 
@@ -90,9 +100,10 @@ class PostsController < ApplicationController
90
100
  end
91
101
  end
92
102
  ```
103
+
93
104
  And that's it. You will now be able to insert the content of any post from within an HTML template using:
94
105
 
95
- {% posts_show id:1234 %}
106
+ `{% posts_show id:1234 %}`
96
107
 
97
108
  This tag will make the browser insert the post content asynchronously into the HTML document.
98
109
 
@@ -104,30 +115,32 @@ Let's use the same example to illustrate the use of cells with xhive.
104
115
 
105
116
  We have a Posts cell and we want to use the show method as an AJAX widget.
106
117
 
107
- ```
108
- app/cells/posts_cell.rb
118
+ `app/cells/posts_cell.rb`
109
119
 
120
+ ```ruby
110
121
  class PostsCell < Cell::Rails
111
122
  def show(params)
112
123
  @post = params[:id]
113
124
  render
114
125
  end
115
126
  end
127
+ ```
116
128
 
117
- app/cells/posts/show.html.erb
129
+ `app/cells/posts/show.html.erb`
118
130
 
131
+ ```erb
119
132
  <div class='post'>
120
133
  <h1><%= @post.title %></h1>
121
134
 
122
135
  <p><%= @post.body %></p>
123
136
  </div>
124
-
125
137
  ```
138
+
126
139
  In this case, we need to tell xhive how we are mounting our widgets routes:
127
140
 
128
- ```
129
- config/initializers/xhive.rb
141
+ `config/initializers/xhive.rb`
130
142
 
143
+ ```ruby
131
144
  Xhive::Router::Cells.draw do |router|
132
145
  router.mount 'posts/:id', :to => 'posts#show'
133
146
  end
@@ -135,12 +148,37 @@ end
135
148
 
136
149
  And that's it. You will now be able to insert the content of any post from within an HTML template using:
137
150
 
138
- {% posts_show id:1234 %}
151
+ `{% posts_show id:1234 %}`
139
152
 
140
153
  This tag will make the browser insert the post content asynchronously into the HTML document.
141
154
 
142
155
  xhive will also enforce the tag to include the :id parameter.
143
156
 
157
+ You can customize the tag invocation name by using the :as symbolized option:
158
+
159
+ ```ruby
160
+ Xhive::Router::Cells.draw do |router|
161
+ router.mount 'posts/:id', :to => 'posts#show', :as => 'show_post'
162
+ end
163
+ ```
164
+ Then you can insert the tag using the following snippet:
165
+
166
+ `{% show_post id:1234 %}`
167
+
168
+ You can also force the cell widget to be rendered inline instead of using AJAX.
169
+
170
+ Just include the :inline symbolized option:
171
+
172
+ ```ruby
173
+ Xhive::Router::Cells.draw do |router|
174
+ router.mount 'posts/:id', :to => 'posts#show', :as => 'show_post', :inline => true
175
+ end
176
+ ```
177
+
178
+ This is also useful when using stylesheet tags inside email pages.
179
+
180
+ Caveat: the inline feature only works for Cell:Base cells.
181
+
144
182
  ## CMS features
145
183
 
146
184
  Ok, I can include my cells and controller actions as widgets, but... how?
@@ -153,13 +191,13 @@ To be able to use your widgets, you have to follow the following steps:
153
191
 
154
192
  Create a Site
155
193
 
156
- ```
194
+ ```ruby
157
195
  site = Xhive::Site.create(:name => 'My awesome blog', :domain => 'localhost')
158
196
  ```
159
197
 
160
198
  Create a Page
161
199
 
162
- ```
200
+ ```ruby
163
201
  page = Xhive::Page.create(:name => 'home',
164
202
  :title => 'My blog page',
165
203
  :content => '<h1>Home</h1><p>{% posts_show id:1 %}</p>',
@@ -180,7 +218,7 @@ xhive provides the Xhive::Mapper to wire up your resources to xhive pages.
180
218
 
181
219
  Create a new page to display all the posts
182
220
 
183
- ```
221
+ ```ruby
184
222
  posts_page = Xhive::Page.create(:name => 'posts',
185
223
  :title => 'Blog Posts',
186
224
  :content => '{% for post in posts %}{% posts_show id:post.id %}{% endfor %}',
@@ -189,7 +227,7 @@ posts_page = Xhive::Page.create(:name => 'posts',
189
227
 
190
228
  Create a new stylesheet to display your posts:
191
229
 
192
- ```
230
+ ```ruby
193
231
  stylesheet = Xhive::Stylesheet.create(:name => 'Posts',
194
232
  :content => '.post {
195
233
  h1 { font-size: 20px; color: blue; }
@@ -200,19 +238,19 @@ stylesheet = Xhive::Stylesheet.create(:name => 'Posts',
200
238
 
201
239
  Create a new mapper record for the posts resources
202
240
 
203
- ```
241
+ ```ruby
204
242
  mapper = Xhive::Mapper.map_resource(site, posts_page, 'posts', 'index')
205
243
  ```
206
244
 
207
245
  If you want to map the page to a specific post
208
246
 
209
- ```
247
+ ```ruby
210
248
  mapper = Xhive::Mapper.map_resource(site, posts_page, 'posts', 'index', post.id)
211
249
  ```
212
250
 
213
251
  From your posts controller, render the posts page
214
252
 
215
- ```
253
+ ```ruby
216
254
  class PostsController < ApplicationController
217
255
  # This will render the page associated with the index action
218
256
  def index
@@ -230,6 +268,70 @@ end
230
268
 
231
269
  Using this feature you can let the designers implement the HTML/CSS to display the posts in your site without your intervention.
232
270
 
271
+ ## ActionMailer integration
272
+
273
+ Using xhive you can extend the CMS capabilities to your system generated emails.
274
+
275
+ ```ruby
276
+ class Notifications < ActionMailer::Base
277
+ def welcome(site, user)
278
+ @user = user
279
+ @link = root_url
280
+
281
+ mailer = Xhive::Mailer.new(site, self)
282
+ mailer.send :to => user.email, :subject => 'Welcome!'
283
+ end
284
+ end
285
+ ```
286
+ In order to use this, you must create a mapper for this specific email action:
287
+
288
+ ```ruby
289
+ mapper = site.mappers.new(:resource => 'notifications', :action => 'welcome')
290
+ mapper.page = my_awesome_email_page
291
+ mapper.save
292
+ ```
293
+
294
+ You can use your instance variables from within the dynamic page:
295
+
296
+ ```
297
+ <p>Dear {{user.first_name}}</p>
298
+
299
+ <p>Welcome to our awesome site</p>
300
+
301
+ <p>Click <a href='{{link}}'>here</a> to start!</p>
302
+
303
+ ```
304
+
305
+ If you want to use different pages for different, e.g. user categories, you can pass the user category to the mailer initializer:
306
+
307
+ ```ruby
308
+ mailer = Xhive::Mailer.new(site, self, user.category)
309
+ ```
310
+
311
+ And you add the key to the mapper creation step:
312
+
313
+ ```ruby
314
+ mapper = site.mappers.new(:resource => 'notifications', :action => 'welcome', :key => 'spanish')
315
+ mapper.page = email_for_spanish_users
316
+ mapper.save
317
+ ```
318
+
319
+ ### Inline stylesheets for your emails
320
+
321
+ If you add the inline widget to your cell routes you can use inline stylesheets within your email pages:
322
+
323
+ ```ruby
324
+ Xhive::Router::Cells.draw do |router|
325
+ router.mount 'stylesheet/:id', :to => 'xhive/stylesheet#inline', :inline => true, :as => :inline_stylesheet
326
+ end
327
+ ```
328
+
329
+ Then you can add your stylesheet into your email page using the corresponding tag:
330
+
331
+ `{% inline_stylesheet id:spain_users_stylesheet %}`
332
+
333
+ This will create a `<style>` tag inside your email page and inject all the style rules.
334
+
233
335
  TODO
234
336
  ====
235
337
 
@@ -238,5 +340,6 @@ TODO
238
340
 
239
341
  Disclaimer
240
342
  ==========
241
- This is a work in progress and still a proof of concept. Use at your own risk :P.
343
+ This is a work in progress and still a proof of concept. Use at your own risk.
242
344
 
345
+ Please let me know of any problems, ideas, improvements, etc.
@@ -0,0 +1,10 @@
1
+ class BaseCell < Cell::Base
2
+ def self.render_action(action, attrs)
3
+ result = Cell::Base.render_cell_for(self.name.underscore, action, attrs)
4
+ rescue e
5
+ result = ''
6
+ logger.error "#{e.class.name}: #{e.message}"
7
+ ensure
8
+ return result
9
+ end
10
+ end
@@ -0,0 +1,8 @@
1
+ module Xhive
2
+ class StylesheetCell < BaseCell
3
+ def inline(params)
4
+ @stylesheet = Xhive::Stylesheet.find(params[:id])
5
+ "<style type='text/css'>#{@stylesheet.presenter.compressed}</style>"
6
+ end
7
+ end
8
+ end
@@ -8,11 +8,21 @@ module Xhive
8
8
  "<link href='#{xhive.stylesheets_path}' media='all' rel='stylesheet' type='text/css'/>".html_safe
9
9
  end
10
10
 
11
- def render_page_with(key = nil, options={})
11
+ # Public: looks for a map and renders the corresponding page.
12
+ #
13
+ # key - The String containing the key to look for (default = nil).
14
+ # options - The Hash the data to pass to the rendered page.
15
+ # block - The block for a custom render if no map is found.
16
+ #
17
+ # Returns: the rendered page.
18
+ #
19
+ def render_page_with(key = nil, options={}, &block)
12
20
  page = Xhive::Mapper.page_for(current_site, controller_path, action_name, key)
13
- render :inline => page.presenter.render_content(options), :layout => true
14
- rescue
15
- render
21
+ if page.present?
22
+ render :inline => page.present_content(options), :layout => true
23
+ else
24
+ block_given? ? yield : render
25
+ end
16
26
  end
17
27
 
18
28
  def current_site
@@ -1,4 +1,6 @@
1
1
  module Xhive
2
+ # Maps resources to pages.
3
+ #
2
4
  class Mapper < ActiveRecord::Base
3
5
  attr_accessible :action, :page_id, :site_id, :resource, :key
4
6
 
@@ -10,13 +12,30 @@ module Xhive
10
12
  validates :site, :presence => true
11
13
  validates :page, :presence => true
12
14
 
15
+ # Public: looks for a page mapper and returns the associated page.
16
+ #
17
+ # site - The Site to look into.
18
+ # resource - The String containing the resource name filter.
19
+ # action - The String containing the action name filter.
20
+ # key - The String containing the key filter.
21
+ #
22
+ # Returns: the mapped page or nil if not found.
23
+ #
13
24
  def self.page_for(site, resource, action, key = nil)
14
25
  mapper = find_map(site, resource, action, key)
15
26
  page = mapper.try(:page)
16
- fail ActiveRecord::RecordNotFound unless page.present?
17
- page
18
27
  end
19
28
 
29
+ # Public: creates a mapper for a specific resource and page.
30
+ #
31
+ # site - The Site to associate the mapper to.
32
+ # page - The Page object to map.
33
+ # resource - The String containing the associated resource name.
34
+ # action - The String containing the associated action name.
35
+ # key - The String containing the associated key.
36
+ #
37
+ # Returns: true if created. False otherwise.
38
+ #
20
39
  def self.map_resource(site, page, resource, action, key = nil)
21
40
  mapper = find_map(site, resource, action, key)
22
41
  mapper = new(:site_id => site.id, :resource => resource, :action => action, :key => key) unless mapper.present?
@@ -26,6 +45,15 @@ module Xhive
26
45
 
27
46
  private
28
47
 
48
+ # Private: looks for a mapper object.
49
+ #
50
+ # site - The Site to look into.
51
+ # resource - The String containing the resource name filter.
52
+ # action - The String containing the action name filter.
53
+ # key - The String containing the key filter.
54
+ #
55
+ # Returns: the mapper object or nil if not found.
56
+ #
29
57
  def self.find_map(site, resource, action, key)
30
58
  mapper = where(:site_id => site.id).where(:resource => resource).where(:action => action)
31
59
  mapper = mapper.where(:key => key) if key.present?
@@ -15,5 +15,9 @@ module Xhive
15
15
  validates :title, :presence => true
16
16
  validates :content, :presence => true
17
17
  validates :site, :presence => true
18
+
19
+ def present_content(opts={})
20
+ presenter.render_content(opts)
21
+ end
18
22
  end
19
23
  end
@@ -6,15 +6,16 @@ module Xhive
6
6
  liquid_methods :name, :title, :content, :meta_keywords, :meta_description
7
7
 
8
8
  def render_content(options={})
9
+ liquified = LiquidWrapper.liquify_objects(options)
9
10
  layout = ::Liquid::Template.parse("{{content}}").render({"content" => page.content})
10
11
  text = ::Liquid::Template.parse(layout).render(
11
- {'page' => self, 'user' => controller.safe_user.presenter}.merge(options.stringify_keys),
12
+ {'page' => self, 'user' => controller.try(:safe_user).try(:presenter)}.merge(liquified.stringify_keys),
12
13
  :registers => {:controller => controller}
13
14
  )
14
15
  result = text.html_safe
15
16
  rescue => e
16
- logger.debug "#{e.class.name}: #{e.message}"
17
- logger.debug e.backtrace.join("/n")
17
+ logger.error "#{e.class.name}: #{e.message}"
18
+ logger.error e.backtrace.join("/n")
18
19
  result = ''
19
20
  ensure
20
21
  return result
@@ -26,11 +26,8 @@ module Xhive
26
26
  def render(context)
27
27
  if (errors = check_parameters).empty?
28
28
  process_parameters(context)
29
- html = "<div "
30
- html << " data-widget='true'"
31
- html << " data-url='#{rest_url}'"
32
- html << " data-params='#{parameters_to_args}'"
33
- html << "></div>"
29
+ route = Xhive::Router::Route.find(rest_url)
30
+ render_inline?(route, context) ? render_inline(route) : render_widget_tag
34
31
  else
35
32
  errors
36
33
  end
@@ -38,6 +35,27 @@ module Xhive
38
35
 
39
36
  private
40
37
 
38
+ def render_widget_tag
39
+ html = "<div "
40
+ html << " data-widget='true'"
41
+ html << " data-url='#{rest_url}'"
42
+ html << " data-params='#{parameters_to_args}'"
43
+ html << "></div>"
44
+ html
45
+ end
46
+
47
+ def render_inline(route)
48
+ # TODO: extend this to the controller based widgets
49
+ result = Cell::Base.render_cell_for(route.klass.underscore, route.action, @attributes)
50
+ rescue NoMethodError
51
+ logger.error "Please check that your cell inherits from Cell:Base and that you are passing all the arguments to the cell action"
52
+ rescue NameError => e
53
+ logger.error "#{e.class.name}: #{e.message}"
54
+ ensure
55
+ return result
56
+ end
57
+
58
+
41
59
  # Private: checks the attributes to see if there is any required
42
60
  # param missing.
43
61
  #
@@ -83,6 +101,12 @@ module Xhive
83
101
  value
84
102
  end
85
103
  end
104
+
105
+ # Private: checks if the tag is for inline rendering or not
106
+ #
107
+ def render_inline?(route, context)
108
+ route.try(:inline) && (context['inline'].nil? || context['inline'])
109
+ end
86
110
  end
87
111
  end
88
112
 
@@ -6,8 +6,6 @@ module Xhive
6
6
 
7
7
  def self.extended(base)
8
8
  base.class_eval do
9
- @@current_controller = nil
10
-
11
9
  include InstanceMethods
12
10
 
13
11
  prepend_before_filter :set_current_controller
data/lib/xhive/engine.rb CHANGED
@@ -12,6 +12,8 @@ module Xhive
12
12
  include Xhive::ApplicationHelper
13
13
 
14
14
  helper_method :initialize_widgets_loader, :include_custom_stylesheets
15
+
16
+ self.class_variable_set('@@current_controller', nil)
15
17
  end
16
18
  end
17
19
  initializer "xhive.load_all_controller_classes", :after=> :disable_dependency_loading do
@@ -0,0 +1,43 @@
1
+ module Xhive
2
+ # Wrapper to add liquid_method to all of object attributes.
3
+ class LiquidWrapper
4
+ def initialize(object)
5
+ @object = object
6
+ end
7
+
8
+ # Public: liquid interface.
9
+ #
10
+ # Returns: object attributes or an empty Array.
11
+ #
12
+ def to_liquid
13
+ @object.respond_to?(:attributes) ? @object.attributes : []
14
+ end
15
+
16
+ # Public: builds wrapper around each collection object.
17
+ #
18
+ # objects - The Hash containing the objects.
19
+ #
20
+ # Returns: the objects hash with the objects wrappers.
21
+ #
22
+ def self.liquify_objects(objects)
23
+ objects.each do |k, v|
24
+ objects[k] = liquify(v)
25
+ end
26
+ end
27
+
28
+ # Public: builds a liquid wrapper around the object.
29
+ #
30
+ # object - The object to wrap.
31
+ #
32
+ # Returns: the same object (if it is already liquified) or a liquid wrapper.
33
+ #
34
+ def self.liquify(object)
35
+ object.respond_to?(:to_liquid) ? object : new(object)
36
+ end
37
+
38
+ # Delegate methods to wrapped object
39
+ def method_missing(sym, *args, &block)
40
+ @object.send sym, *args, &block
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,60 @@
1
+ module Xhive
2
+ class Mailer
3
+ attr :site, :resource, :action, :key, :mailer, :content
4
+
5
+ def initialize(site, mailer, key = nil)
6
+ @site = site
7
+ @resource = mailer.class.name.underscore
8
+ @mailer = mailer
9
+ @action = mailer.action_name
10
+ @key = key
11
+ end
12
+
13
+ # Public: sends the email to the specified recipients.
14
+ #
15
+ # opts - The Hash containing the email sending options.
16
+ #
17
+ # :from
18
+ # :to
19
+ # :reply_to
20
+ # :subject
21
+ #
22
+ # block - The block for customizing the email sending.
23
+ #
24
+ def send(opts = {}, &block)
25
+ unless block_given?
26
+ mailer.send(:mail, opts) do |format|
27
+ format.html { mailer.render :text => content }
28
+ end
29
+ else
30
+ yield content
31
+ end
32
+ end
33
+
34
+ # Public: returns the email content body.
35
+ #
36
+ # Returns: the rendered template or the mapped page content body.
37
+ #
38
+ def content
39
+ return @content if @content.present?
40
+ page = Xhive::Mapper.page_for(site, resource, action, key)
41
+ @content = page.present? ? page.present_content(mailer_instance_variables(mailer)) : mailer.render
42
+ end
43
+
44
+ private
45
+
46
+ # Private: extracts the instance variables from the mailer object.
47
+ #
48
+ # mailer - The ActionMailer::Base object.
49
+ #
50
+ # Returns: a Hash with all the instance variables instantiated.
51
+ #
52
+ def mailer_instance_variables(mailer)
53
+ internal_vars = [:@_routes, :@_action_has_layout, :@_message, :@_prefixes, :@_lookup_context, :@_action_name, :@_response_body]
54
+ vars = mailer.instance_variables - internal_vars
55
+ opts = {}
56
+ vars.each {|v| opts[v.slice(1..-1).to_sym] = mailer.instance_variable_get(v)}
57
+ opts
58
+ end
59
+ end
60
+ end
@@ -39,9 +39,9 @@ module Xhive
39
39
  cell, action = options[:to].split('#')
40
40
  widgets_base_route = Base.route_for('widgets', 'show').gsub(/\/\*\w*$/, '')
41
41
  widget_route = "#{widgets_base_route}/#{path}"
42
- tag_class_name = "#{cell}_#{action}".camelize
42
+ tag_class_name = (options[:as] || "#{cell}_#{action}").to_s.classify.gsub('::', '')
43
43
 
44
- Route.add(widget_route, cell.camelize, action)
44
+ Route.add(widget_route, cell, action, options.except(:to))
45
45
 
46
46
  Xhive::TagFactory.create_class(tag_class_name, widget_route)
47
47
  end
@@ -3,13 +3,15 @@ module Xhive
3
3
  class Route
4
4
  @@routes = []
5
5
 
6
- attr :route, :klass, :action, :args
6
+ attr :route, :klass, :action, :args, :inline, :as
7
7
 
8
- def initialize(route, klass, action)
8
+ def initialize(route, klass, action, opts={})
9
9
  @route = route
10
10
  @klass = klass
11
11
  @action = action
12
12
  @args = extract_args(route)
13
+ @inline = opts[:inline] || false
14
+ @as = opts[:as].to_s || klass
13
15
  end
14
16
 
15
17
  # Public: adds a new route to the collection.
@@ -17,9 +19,10 @@ module Xhive
17
19
  # route - The String containing the route definition.
18
20
  # klass - The String containing the Controller/Cell class name.
19
21
  # action - The String containing the action name.
22
+ # inline - The Boolean indicating if it should be rendered inline or as an AJAX widget.
20
23
  #
21
- def self.add(route, klass, action)
22
- @@routes << new(route, klass, action)
24
+ def self.add(route, klass, action, inline)
25
+ @@routes << new(route, klass, action, inline)
23
26
  end
24
27
 
25
28
  # Public: finds the route that matches the url.
data/lib/xhive/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Xhive
2
- VERSION = "1.0.9.pre"
2
+ VERSION = "1.2.0.pre"
3
3
  end
data/lib/xhive.rb CHANGED
@@ -4,6 +4,8 @@ module Xhive
4
4
  end
5
5
 
6
6
  require 'xhive/hashy'
7
+ require 'xhive/liquid_wrapper'
8
+ require 'xhive/mailer'
7
9
  require 'xhive/controller'
8
10
  require 'xhive/presentable'
9
11
  require 'xhive/router'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xhive
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.9.pre
4
+ version: 1.2.0.pre
5
5
  prerelease: 6
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-11-02 00:00:00.000000000 Z
12
+ date: 2012-11-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -156,7 +156,23 @@ dependencies:
156
156
  - !ruby/object:Gem::Version
157
157
  version: '0'
158
158
  - !ruby/object:Gem::Dependency
159
- name: shoulda
159
+ name: shoulda-context
160
+ requirement: !ruby/object:Gem::Requirement
161
+ none: false
162
+ requirements:
163
+ - - ! '>='
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ type: :development
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ none: false
170
+ requirements:
171
+ - - ! '>='
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ - !ruby/object:Gem::Dependency
175
+ name: shoulda-matchers
160
176
  requirement: !ruby/object:Gem::Requirement
161
177
  none: false
162
178
  requirements:
@@ -216,6 +232,8 @@ files:
216
232
  - app/assets/javascripts/xhive/pages.js
217
233
  - app/assets/stylesheets/xhive/application.css
218
234
  - app/assets/stylesheets/xhive/pages.css
235
+ - app/cells/base_cell.rb
236
+ - app/cells/xhive/stylesheet_cell.rb
219
237
  - app/controllers/xhive/application_controller.rb
220
238
  - app/controllers/xhive/images_controller.rb
221
239
  - app/controllers/xhive/pages_controller.rb
@@ -250,6 +268,8 @@ files:
250
268
  - lib/xhive/controller.rb
251
269
  - lib/xhive/engine.rb
252
270
  - lib/xhive/hashy.rb
271
+ - lib/xhive/liquid_wrapper.rb
272
+ - lib/xhive/mailer.rb
253
273
  - lib/xhive/presentable.rb
254
274
  - lib/xhive/router/base.rb
255
275
  - lib/xhive/router/cells.rb
@@ -277,7 +297,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
277
297
  version: '0'
278
298
  segments:
279
299
  - 0
280
- hash: -1538157182709527364
300
+ hash: -4002595324166210209
281
301
  required_rubygems_version: !ruby/object:Gem::Requirement
282
302
  none: false
283
303
  requirements: