xhive 1.4.0.pre → 1.5.0.pre

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.
data/README.md CHANGED
@@ -268,6 +268,26 @@ end
268
268
 
269
269
  Using this feature you can let the designers implement the HTML/CSS to display the posts in your site without your intervention.
270
270
 
271
+ ## Policy based mapping
272
+
273
+ If you need more customization in the page mapping process, you can pass a policy class name as the last attribute.
274
+
275
+ ```ruby
276
+ class MyPolicyClass
277
+ def call(opts={})
278
+ opts[:user].country == 'US' && opts[:user].age > 18
279
+ end
280
+ end
281
+
282
+ mapper = Xhive::Mapper.map_resource(site, posts_page, 'posts', 'index', post.id, 'MyPolicyClass')
283
+
284
+ # It will only use the page if the user is an adult from the US
285
+ render_page_with @post.id, :post => @post, :user => @user
286
+
287
+ ```
288
+ Note: the mailer instance variables will be passed along to the policy class. This allows you to customize the email templates
289
+ depending on the user properties. See below for ActionMailer integration.
290
+
271
291
  ## ActionMailer integration
272
292
 
273
293
  Using xhive you can extend the CMS capabilities to your system generated emails.
@@ -316,6 +336,9 @@ mapper.page = email_for_spanish_users
316
336
  mapper.save
317
337
  ```
318
338
 
339
+ Note: the page title will be used as the email subject. You can also make use of the instance variables
340
+ inside the page title as is treated as a Liquid template string.
341
+
319
342
  ### Inline stylesheets for your emails
320
343
 
321
344
  If you add the inline widget to your cell routes you can use inline stylesheets within your email pages:
@@ -346,14 +369,17 @@ Then you can add your inline page into your email page using the corresponding t
346
369
 
347
370
  `{% inline_page id:email_header %}`
348
371
 
349
- TODO
350
- ====
372
+ ## TODO
351
373
 
352
374
  * Remove as many dependencies as possible
353
375
  * Improve test coverage
354
376
 
355
- Disclaimer
356
- ==========
377
+ ## Disclaimer
378
+
357
379
  This is a work in progress and still a proof of concept. Use at your own risk.
358
380
 
359
381
  Please let me know of any problems, ideas, improvements, etc.
382
+
383
+ ## Special Thanks
384
+
385
+ * Thanks to [Daniel Cadenas](https://github.com/dcadenas) for the Policy class inspiration.
@@ -17,7 +17,7 @@ module Xhive
17
17
  # Returns: the rendered page.
18
18
  #
19
19
  def render_page_with(key = nil, options={}, &block)
20
- page = Xhive::Mapper.page_for(current_site, controller_path, action_name, key)
20
+ page = Xhive::Mapper.page_for(current_site, controller_path, action_name, key, options)
21
21
  if page.present?
22
22
  render :inline => page.present_content(options), :layout => true
23
23
  else
@@ -2,7 +2,7 @@ module Xhive
2
2
  # Maps resources to pages.
3
3
  #
4
4
  class Mapper < ActiveRecord::Base
5
- attr_accessible :action, :page_id, :site_id, :resource, :key
5
+ attr_accessible :action, :page_id, :site_id, :resource, :key, :policy
6
6
 
7
7
  belongs_to :site
8
8
  belongs_to :page
@@ -18,11 +18,12 @@ module Xhive
18
18
  # resource - The String containing the resource name filter.
19
19
  # action - The String containing the action name filter.
20
20
  # key - The String containing the key filter.
21
+ # opts - The Hash containing extra values for policy-based filters.
21
22
  #
22
23
  # Returns: the mapped page or nil if not found.
23
24
  #
24
- def self.page_for(site, resource, action, key = nil)
25
- mapper = find_map(site, resource, action, key)
25
+ def self.page_for(site, resource, action, key = nil, opts = {})
26
+ mapper = find_map(site, resource, action, key, opts)
26
27
  page = mapper.try(:page)
27
28
  end
28
29
 
@@ -33,13 +34,17 @@ module Xhive
33
34
  # resource - The String containing the associated resource name.
34
35
  # action - The String containing the associated action name.
35
36
  # key - The String containing the associated key.
37
+ # policy - The String containing the policy class.
36
38
  #
37
39
  # Returns: true if created. False otherwise.
38
40
  #
39
- def self.map_resource(site, page, resource, action, key = nil)
40
- mapper = find_map(site, resource, action, key)
41
+ def self.map_resource(site, page, resource, action, key = nil, policy = nil)
42
+ check_policy_class(policy) if policy.present?
43
+
44
+ mapper = find_exact_map(site, resource, action, key, policy)
41
45
  mapper = new(:site_id => site.id, :resource => resource,
42
- :action => action, :key => key.present? ? key : nil) unless mapper.present?
46
+ :action => action, :policy => policy,
47
+ :key => key.present? ? key : nil) unless mapper.present?
43
48
  mapper.page = page
44
49
  mapper.save
45
50
  end
@@ -55,6 +60,16 @@ module Xhive
55
60
  where(:site_id => site.id).where(:resource => resource)
56
61
  end
57
62
 
63
+ class InvalidPolicyError < StandardError
64
+ def initialize(name)
65
+ @name = name
66
+ end
67
+
68
+ def message
69
+ "#{@name} must implement a ::call method"
70
+ end
71
+ end
72
+
58
73
  private
59
74
 
60
75
  # Private: looks for a mapper object.
@@ -63,15 +78,75 @@ module Xhive
63
78
  # resource - The String containing the resource name filter.
64
79
  # action - The String containing the action name filter.
65
80
  # key - The String containing the key filter.
81
+ # opts - The Hash containing extra values for policy-based filters.
82
+ #
83
+ # Returns:
84
+ #
85
+ # - The mapper object if it finds a key.
86
+ # - The default mapper if it does not find a key.
87
+ # - Nil if there is no default mapper.
88
+ #
89
+ def self.find_map(site, resource, action, key, opts)
90
+ # Create filtering scopes
91
+ scope = where(:site_id => site.id)
92
+ scope = scope.where(:resource => resource)
93
+ scope = scope.where(:action => action)
94
+
95
+ # Fetch mappers
96
+ mappers = scope.where(:key => key.present? ? key : nil)
97
+ mappers = scope.where(:key => nil) if mappers.empty?
98
+
99
+ # Check policies and select the first that passes
100
+ select_by_policy(mappers, opts)
101
+ end
102
+
103
+ # Private: looks for an exact mapper object.
104
+ #
105
+ # site - The Site to look into.
106
+ # resource - The String containing the resource name filter.
107
+ # action - The String containing the action name filter.
108
+ # key - The String containing the key filter.
109
+ # policy - The String containing the policy class.
66
110
  #
67
111
  # Returns: the mapper object or nil if not found.
68
112
  #
69
- def self.find_map(site, resource, action, key)
113
+ def self.find_exact_map(site, resource, action, key, policy)
70
114
  mapper = where(:site_id => site.id)
71
115
  mapper = mapper.where(:resource => resource)
72
116
  mapper = mapper.where(:action => action)
73
117
  mapper = mapper.where(:key => key.present? ? key : nil)
118
+ mapper = mapper.where(:policy => policy.present? ? policy : nil)
74
119
  mapper.first
75
120
  end
121
+
122
+ # Private: selects the first mapper that fulfills the policy
123
+ #
124
+ # mappers - The Array containing the mapper objects.
125
+ # opts - The Hash containing the policy filter data.
126
+ #
127
+ # Returns: the first matching mapper or nil if no one matches
128
+ #
129
+ def self.select_by_policy(mappers, opts)
130
+ mappers.sort_by {|m| m.policy.to_s }.reverse.select {|m| m.send(:verify_policy, opts) }.first
131
+ end
132
+
133
+ # Private: checks the mapper policy against its class
134
+ #
135
+ # opts - The Hash containing the policy filter data.
136
+ #
137
+ # Return: true if it fulfills the policy and false if it does not.
138
+ #
139
+ def verify_policy(opts)
140
+ result = policy.constantize.call(opts)
141
+ rescue NameError
142
+ result = true
143
+ ensure
144
+ return result
145
+ end
146
+
147
+ def self.check_policy_class(policy)
148
+ klass = policy.constantize
149
+ fail InvalidPolicyError.new(policy) unless klass.respond_to?(:call)
150
+ end
76
151
  end
77
152
  end
@@ -0,0 +1,5 @@
1
+ class AddPolicyToXhiveMappers < ActiveRecord::Migration
2
+ def change
3
+ add_column :xhive_mappers, :policy, :string, :null => true, :default => nil
4
+ end
5
+ end
data/lib/xhive/mailer.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module Xhive
2
2
  class Mailer
3
- attr :site, :resource, :action, :key, :mailer, :content, :page
3
+ attr :site, :resource, :action, :key, :mailer, :content, :page, :vars
4
4
 
5
5
  def initialize(site, mailer, key = nil)
6
6
  @site = site
@@ -8,7 +8,8 @@ module Xhive
8
8
  @mailer = mailer
9
9
  @action = mailer.action_name
10
10
  @key = key
11
- @page = Xhive::Mapper.page_for(@site, @resource, @action, @key)
11
+ @vars = mailer_instance_variables(mailer)
12
+ @page = Xhive::Mapper.page_for(@site, @resource, @action, @key, @vars)
12
13
  end
13
14
 
14
15
  # Public: sends the email to the specified recipients.
@@ -38,7 +39,7 @@ module Xhive
38
39
  #
39
40
  def content
40
41
  return @content if @content.present?
41
- @content = page.present? ? page.present_content(mailer_instance_variables(mailer)) : mailer.render
42
+ @content = page.present? ? page.present_content(vars) : mailer.render
42
43
  end
43
44
 
44
45
  # Public: returns the email subject.
@@ -46,7 +47,7 @@ module Xhive
46
47
  # Returns: the rendered template or the mapped page content body.
47
48
  #
48
49
  def subject
49
- @subject = page.present? ? page.present_title(mailer_instance_variables(mailer)) : nil
50
+ @subject = page.present? ? page.present_title(vars) : nil
50
51
  end
51
52
 
52
53
  private
data/lib/xhive/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Xhive
2
- VERSION = "1.4.0.pre"
2
+ VERSION = "1.5.0.pre"
3
3
  end
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.4.0.pre
4
+ version: 1.5.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-22 00:00:00.000000000 Z
12
+ date: 2012-11-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -187,22 +187,6 @@ dependencies:
187
187
  - - ! '>='
188
188
  - !ruby/object:Gem::Version
189
189
  version: '0'
190
- - !ruby/object:Gem::Dependency
191
- name: debugger
192
- requirement: !ruby/object:Gem::Requirement
193
- none: false
194
- requirements:
195
- - - ! '>='
196
- - !ruby/object:Gem::Version
197
- version: '0'
198
- type: :development
199
- prerelease: false
200
- version_requirements: !ruby/object:Gem::Requirement
201
- none: false
202
- requirements:
203
- - - ! '>='
204
- - !ruby/object:Gem::Version
205
- version: '0'
206
190
  - !ruby/object:Gem::Dependency
207
191
  name: mocha
208
192
  requirement: !ruby/object:Gem::Requirement
@@ -264,6 +248,7 @@ files:
264
248
  - db/migrate/20121019185702_create_xhive_mappers.rb
265
249
  - db/migrate/20121031192552_add_key_to_xhive_mappers.rb
266
250
  - db/migrate/20121101124925_create_xhive_images.rb
251
+ - db/migrate/20121127230527_add_policy_to_xhive_mappers.rb
267
252
  - lib/tasks/xhive_tasks.rake
268
253
  - lib/xhive/base_tag.rb
269
254
  - lib/xhive/controller.rb
@@ -298,7 +283,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
298
283
  version: '0'
299
284
  segments:
300
285
  - 0
301
- hash: 679411744217455480
286
+ hash: -2539444549338109190
302
287
  required_rubygems_version: !ruby/object:Gem::Requirement
303
288
  none: false
304
289
  requirements: