orthorings 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -5,13 +5,13 @@ Orthorings is a gem to interact with and display content from Orthor.com
5
5
  The 2 main things you can do with Orthorings are:
6
6
 
7
7
  * Define an entire site backed by Orthor with the included DSL (more on this below)
8
- * Display content on any page in your app using the included helper methods and the Orthorings class
8
+ * Display content on any page in your app using the included helper methods
9
9
 
10
10
  ## Installation
11
11
 
12
- As a gem
13
-
14
- gem install orthorings
12
+ As a gem
13
+
14
+ gem install orthorings
15
15
 
16
16
  ## Configuration
17
17
 
@@ -31,63 +31,128 @@ To make creating a new site backed by Orthor super easy, we've included a DSL th
31
31
  Here is some example usage (more docs to come, this is still a WIP and some aspects will change)
32
32
 
33
33
  Orthor::Site.define do
34
- cache_for 300 # in seconds, http caching
35
- layout :application
36
- keywords "your, site, specific, keywords"
37
- description "what's your site doing?"
38
-
39
- page "/", "home"
40
- page "/about"
41
-
42
- feed "/blog.rss", "our-blog" do
43
- name "Our Blog Feed"
44
- end
45
-
46
- static_page "/about-us" do
47
- view "public/about_us"
34
+ layout :layout
35
+ keywords "cms, content management, pluggable"
36
+ description "pluggable content management service"
37
+
38
+ with_template :basic_content do
39
+ page "/", :id => "what-is-orthor", :view => :home
40
+ page "/about"
41
+ page "/terms"
42
+ page "/contact", :view => :contact
48
43
  end
49
44
 
50
- query "/latest-news"
51
-
52
- category "/writings" do
53
- keywords "lets, do, some, seo"
54
- description "a more apt description for this section of the site"
55
- view "writings/index"
56
-
57
- page "/writings/why", "Why we write"
58
- page_path "/writings/:id"
59
-
60
- feed "/writings.rss" do
61
- id "our-writings"
62
- name "Our Writings"
63
- end
64
-
65
- category "/writings/announcements" do
66
- view "writings/announcements"
67
- page_path "/writings/announcements/:id"
68
- end
69
- end
45
+ feed "/news_and_blog.rss", :id => "news-blog-entries"
46
+ feed "/news.rss", :id => "news"
47
+ feed "/blog.rss", :id => "blog"
48
+ feed "/manual.rss", :id => "manual"
49
+
50
+ category "/manual", :page_path => "/manual/:id",
51
+ :template => :user_manual
52
+ category "/news", :template => :news_item
53
+ category "/blog", :template => :blog_entry_brief,
54
+ :page_path => "/blog/:id",
55
+ :page_template => :blog_entry
70
56
  end
71
57
 
72
- In the above example, every route defined will be handled by the Orthorings gem and rendered through your specified layout, easy! In rails, you will also get named routes based off of the orthor id, e.g.
58
+ ### Options
59
+
60
+ :id - the orthor id of your element
61
+ :view - specify the path to a view file you'd like to render this content with
62
+ :template - the template to use when rendering your content
63
+ :keywords - what meta keywords you'd like to use on this page
64
+ :description - what meta description you'd like shown on this page
65
+
66
+ #### Category specific
67
+
68
+ :page_path - what path to use for your pages inside a category
69
+ :page_template - what template to use to display a page inside a category
70
+
71
+ #### Feed specific
72
+
73
+ :name - The name of your feed, used in the feed_helpers
74
+
75
+ In the above example, every route defined will be handled by the Orthorings gem and rendered through your specified layout, easy! In rails, you will also get named routes based off of the orthor id, e.g.
73
76
 
74
77
  "our-blog" -> our_blog_path
75
78
 
76
- Inside of any block in the dsl, you can specify the orthor id, if you don't give an id, the dsl assumes the last fragment of the specified path is the orthor object id, e.g. "/writings" has an orthor id of "writings". Stay tuned for more examples and documentation.
79
+ ## Templates
80
+
81
+ Your content from Orthor comes down in JSON, so for every piece of content you want to display, you need to provide a HTML template. Some example templates are shown below. Every piece of content you get back has the same attributes (e.g. "Published on", "Created by") plus every content widget on your template indexed by name.
82
+
83
+ When you define your pages etc, you can tell it which template to use with a :template argument. If you use the helper methods (explained below) you can pass in the template name.
84
+
85
+ Orthor::Templates.define do
86
+ template :basic_content, %(<div>{{Content}}</div>)
87
+
88
+ template :blog_entry, %(
89
+ <div class="blog-entry">
90
+ <h2>{{Title}}</h2>
91
+ <div class="blog-content">{{Wysiwyg}}</div>
92
+ </div>)
93
+ template :blog_entry_brief, %(
94
+ <div class="blog-entry">
95
+ <h2><a href="{{URL}}">{{Title}}</a></h2>
96
+ <div class="blog-content">{{Wysiwyg.blurb}}</div>
97
+ </div>)
98
+
99
+ template :user_manual, %(
100
+ <div class="user-manual-entry">
101
+ <h2>{{Title}}</h2>
102
+ <p class="last-updated">Last updated: {{Updated on}}</p>
103
+ <div class="content">{{Wysiwyg}}</div>
104
+ </div>)
105
+ end
77
106
 
78
- ## TODO
79
107
 
80
- Things that are being mulled over
108
+ ### Template tags
109
+
110
+ These tags are available to all content:
111
+
112
+ {{Title}} - your content title
113
+ {{Created on}} - the date your content was created
114
+ {{Updated on}} - the date your content was last updated
115
+ {{Created by}} - a hash of the creator details
116
+ {{Updated by}} - a hash of the updater details
117
+ {{Published on}} - the date your content was published
118
+ {{URL}} - the URL for your content as defined in Orthor, or auto generated as /category-id/content-id
119
+
120
+ Other attributes that will be present on a per item specific basis are the names of your template elements, e.g.
121
+
122
+ {{Content}}
123
+ {{Featured News Item}}
124
+ {{Supporting Image}}
125
+ {{Markdown body}}
81
126
 
82
- * Nav helpers (generate navigation based off of the DSL structure)
83
- * ...I'm sure there'll be something else here soon
84
127
 
85
128
  ## Example Usage (as provided by the OrthorHelper module, defined as class methods of Orthorings)
86
129
 
87
- orthor_content("content-item-id") or Orthorings.content("id")
88
- orthor_query("query-id") or Orthorings.query("id")
89
- orthor_category("category-id") or Orthorings.category("id")
130
+ In all the methods below, if you don't provide a template name, you will get the parsed JSON array/hash back.
131
+
132
+ ### Content
133
+
134
+ orthor_content("content-item-id", :template_name)
135
+ Orthorings.content("id", :template_name)
136
+
137
+ ### Queries
138
+
139
+ orthor_query("query-id", :template_name)
140
+ Orthorings.query("id", :template_name)
141
+
142
+ ### Categories
143
+
144
+ orthor_category("category-id", :template_name)
145
+ Orthorings.category("id", :template_name)
146
+
147
+ ### Feeds
148
+
90
149
  orthor_feed("feed-id") or Orthorings.feed("id")
91
150
 
151
+ ### Meta data
152
+
153
+ keywords - render a <meta> keywords tag for the current piece of content (or the default site keywords)
154
+ description - render a <meta> description tag for the current piece of content (or the default site description)
155
+ orthor_feed_tags - render a <link> tag for all of your defined feeds
156
+
92
157
 
93
158
  Copyright (c) 2009 Robotic Foo, released under the MIT license
data/Rakefile CHANGED
@@ -6,11 +6,12 @@ begin
6
6
  require 'jeweler'
7
7
  Jeweler::Tasks.new do |gem|
8
8
  gem.name = "orthorings"
9
- gem.summary = "Orthorings is a gem for displaying content from orthor.com"
9
+ gem.summary = "A gem for displaying content from orthor.com"
10
10
  gem.email = "anthony@orthor.com"
11
11
  gem.homepage = "http://github.com/anthony/orthorings"
12
12
  gem.authors = ["Anthony Langhorne"]
13
13
  gem.add_dependency("moneta", "0.6.0")
14
+ gem.add_dependency("json")
14
15
  end
15
16
  Jeweler::GemcutterTasks.new
16
17
  rescue LoadError
@@ -21,4 +22,4 @@ desc "Run all the Orthorings specs"
21
22
  Spec::Rake::SpecTask.new(:ospec) do |t|
22
23
  t.spec_opts = ['--options', "spec/spec.opts"]
23
24
  t.spec_files = FileList['spec/**/*_spec.rb']
24
- end
25
+ end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.1
1
+ 0.4.0
@@ -1,15 +1,15 @@
1
1
  class OrthorContentController < ApplicationController
2
2
  def orthor_content
3
3
  expires_in Orthor::Site.cache_for, :public => true if Orthor::Site.cache_for > 0
4
-
4
+
5
5
  if params[:id]
6
- @orthor_content = Orthorings.content(params[:id])
7
6
  resource = Orthor::Site.find_resource_by_page_path(request.request_uri, params[:id])
8
- else
7
+ @orthor_content = Orthorings.content(params[:id], (resource.page_template || resource.template))
8
+ else
9
9
  resource = Orthor::Site.find_resource_by_path(request.request_uri)
10
10
  @orthor_content = resource.content
11
11
  end
12
-
12
+
13
13
  if resource.is_a?(Orthor::Feed)
14
14
  render :xml => @orthor_content
15
15
  else
@@ -17,7 +17,7 @@ class OrthorContentController < ApplicationController
17
17
  @meta_keywords = resource.keywords
18
18
  @meta_description = resource.description
19
19
  @orthor_feeds = resource.respond_to?(:feeds) ? resource.feeds : []
20
-
20
+
21
21
  render :action => (resource.view || "orthor_content"), :layout => Orthor::Site.layout.to_s
22
22
  end
23
23
  end
@@ -2,15 +2,18 @@ module Orthor
2
2
  class Category < Orthor::Object
3
3
  include Orthor::Collections
4
4
 
5
- dsl_accessor :page_path
5
+ dsl_accessor :page_path, :page_template
6
6
 
7
- def initialize(path, category_name, &block)
7
+ def initialize(path, options = {}, &blk)
8
8
  @feeds, @categories, @pages, @static_pages, @queries = [], [], [], [], []
9
- super path, category_name, &block
9
+ super path, options
10
+
11
+ # categories can give blocks
12
+ instance_eval &blk if block_given?
10
13
  end
11
-
14
+
12
15
  def fetch_content
13
- Orthorings.category(@id)
16
+ Orthorings.category(@id, @template)
14
17
  end
15
18
  end
16
19
  end
@@ -2,26 +2,26 @@ module Orthor
2
2
  module Collections
3
3
  attr_accessor :feeds, :categories, :pages, :static_pages, :queries
4
4
 
5
- def feed(path, name = nil, &block)
6
- feeds << Orthor::Feed.new(path, name, &block)
5
+ def page(path, options = {}, &block)
6
+ pages << Orthor::Page.new(path, options, &block)
7
7
  end
8
8
 
9
- def category(path, name = nil, &block)
10
- categories << Orthor::Category.new(path, name, &block)
9
+ def category(path, options = {}, &block)
10
+ categories << Orthor::Category.new(path, options, &block)
11
11
  end
12
12
 
13
- def page(path, name = nil, &block)
14
- pages << Orthor::Page.new(path, name, &block)
13
+ def query(path, options = {}, &block)
14
+ queries << Orthor::Query.new(path, options, &block)
15
15
  end
16
16
 
17
- def static_page(path, name = nil, &block)
18
- static_pages << Orthor::StaticPage.new(path, name, &block)
19
- end
17
+ def feed(path, options = {}, &block)
18
+ feeds << Orthor::Feed.new(path, options, &block)
19
+ end
20
20
 
21
- def query(path, name = nil, &block)
22
- queries << Orthor::Query.new(path, name, &block)
21
+ def static_page(path, options = {}, &block)
22
+ static_pages << Orthor::StaticPage.new(path, options, &block)
23
23
  end
24
-
24
+
25
25
  def resources
26
26
  return [] unless @feeds && @pages && @static_pages && @categories && @queries
27
27
  ((@feeds + @pages + @static_pages + @categories + @queries) + @categories.collect { |category| category.resources }).flatten
data/lib/orthor/object.rb CHANGED
@@ -4,24 +4,25 @@ module Orthor
4
4
  include Orthor::MetaData
5
5
 
6
6
  attr_accessor :path
7
- dsl_accessor :name, :id, :view
7
+ dsl_accessor :id, :view, :template, :name
8
8
 
9
- def initialize(path, id = nil, &block)
9
+ def initialize(path, options = {})
10
10
  @path = path
11
- raise "Path required" unless @path
12
- @id = id || @path.split("/").last
11
+ raise ArgumentError, "Path required" unless @path
13
12
 
14
- instance_eval &block if block_given?
13
+ options.each { |key, val| send(key, val) }
14
+ @id ||= @path.split("/").last
15
+ @template ||= Orthor::Site.current_template
15
16
  end
16
-
17
+
17
18
  def content
18
19
  fetch_content
19
20
  end
20
-
21
+
21
22
  def path_name
22
23
  @id.gsub(/[^a-z0-9]+/i, '_')
23
24
  end
24
-
25
+
25
26
  def fetch_content
26
27
  raise "This must be overriden in any Orthor::Object subclass"
27
28
  end
data/lib/orthor/page.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  module Orthor
2
2
  class Page < Orthor::Object
3
3
  def fetch_content
4
- Orthorings.content(@id)
4
+ Orthorings.content(@id, @template)
5
5
  end
6
6
  end
7
- end
7
+ end
data/lib/orthor/query.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  module Orthor
2
2
  class Query < Orthor::Object
3
3
  def fetch_content
4
- Orthorings.query(@id)
4
+ Orthorings.query(@id, @template)
5
5
  end
6
6
  end
7
7
  end
data/lib/orthor/site.rb CHANGED
@@ -4,23 +4,31 @@ module Orthor
4
4
  include Orthor::Collections
5
5
  include Orthor::HttpCaching
6
6
  include Orthor::MetaData
7
-
7
+
8
8
  dsl_accessor :layout
9
+ attr_accessor :current_template
9
10
 
10
- def define(&block)
11
+ def define(&blk)
11
12
  @feeds, @categories, @pages, @static_pages, @queries = [], [], [], [], []
12
- layout(:orthor_layout)
13
+ layout(:orthor_layout)
13
14
  cache_for 0
14
15
  keywords ""
15
16
  description ""
16
17
 
17
- class_eval &block
18
+ class_eval &blk
19
+ end
20
+
21
+ def with_template(name, &blk)
22
+ raise ArgumentError, "block required" unless block_given?
23
+ @current_template = name
24
+ class_eval &blk
25
+ @current_template = nil
18
26
  end
19
-
27
+
20
28
  def find_resource_by_path(path)
21
29
  Orthor::Site.resources.detect { |r| r.path == path }
22
30
  end
23
-
31
+
24
32
  def find_resource_by_page_path(path, id)
25
33
  Orthor::Site.resources.detect { |r| r.is_a?(Orthor::Category) && r.page_path.gsub(":id", id) == path }
26
34
  end
@@ -4,14 +4,13 @@ module Orthor
4
4
  include Orthor::MetaData
5
5
 
6
6
  attr_accessor :path
7
- dsl_accessor :name, :view, :controller
7
+ dsl_accessor :view, :controller
8
8
 
9
- def initialize(path, page_name, &block)
9
+ def initialize(path, options = {})
10
10
  @path = path
11
- name(page_name)
12
- raise "Path required" unless @path
11
+ raise ArgumentError, "Path required" unless @path
13
12
 
14
- instance_eval &block if block_given?
13
+ options.each { |key, val| send(key, val) }
15
14
  end
16
15
 
17
16
  def path_name
@@ -0,0 +1,22 @@
1
+ module Orthor
2
+ class Templates
3
+ class << self
4
+ attr_accessor :templates
5
+
6
+ def define(&blk)
7
+ @templates = {}
8
+ class_eval &blk
9
+ end
10
+
11
+ def template(name, markup)
12
+ @templates[name.to_s] = markup
13
+ end
14
+ alias :add :template
15
+
16
+ def [](key)
17
+ @templates ||= {}
18
+ @templates[key.to_s]
19
+ end
20
+ end
21
+ end
22
+ end
data/lib/orthor_helper.rb CHANGED
@@ -1,32 +1,32 @@
1
1
  module OrthorHelper
2
- def orthor_content(id)
3
- return Orthorings.content(id)
2
+ def orthor_content(id, template = nil)
3
+ return Orthorings.content(id, template)
4
4
  end
5
-
6
- def orthor_category(id)
7
- return Orthorings.category(id)
5
+
6
+ def orthor_category(id, template = nil)
7
+ return Orthorings.category(id, template)
8
8
  end
9
-
10
- def orthor_query(id)
11
- return Orthorings.query(id)
9
+
10
+ def orthor_query(id, template = nil)
11
+ return Orthorings.query(id, template)
12
12
  end
13
-
13
+
14
14
  def orthor_feed(id)
15
15
  return Orthorings.feed(id)
16
16
  end
17
-
17
+
18
18
  def keywords
19
19
  content = @meta_keywords || Orthor::Site.keywords
20
20
  return if content.nil? || content.empty?
21
21
  %Q(<meta content="#{content}" name="keywords" />)
22
22
  end
23
-
23
+
24
24
  def description
25
25
  content = @meta_description || Orthor::Site.description
26
26
  return if content.nil? || content.empty?
27
27
  %Q(<meta content="#{content}" name="description" />)
28
28
  end
29
-
29
+
30
30
  def orthor_feed_tags
31
31
  (Orthor::Site.feeds + (@orthor_feeds.nil? ? [] : @orthor_feeds)).inject("") do |html, feed|
32
32
  html += %Q(<link rel="alternate" type="application/rss+xml" title="#{feed.name || "RSS"}" href="#{feed.path}" />)
data/lib/orthorings.rb CHANGED
@@ -1,33 +1,44 @@
1
- Dir[File.dirname(__FILE__) + '/core_ext/*.rb'].each { |e| require e }
2
- %w(orthor/http_caching orthor/meta_data orthor/collections orthor/site orthor/object orthor/category orthor/feed orthor/page orthor/static_page orthor/query).each { |r| require File.join(File.dirname(__FILE__), r) }
1
+ require 'core_ext/dsl_accessor'
2
+
3
+ require 'orthor/http_caching'
4
+ require 'orthor/templates'
5
+ require 'orthor/meta_data'
6
+ require 'orthor/collections'
7
+ require 'orthor/site'
8
+ require 'orthor/object'
9
+ require 'orthor/category'
10
+ require 'orthor/feed'
11
+ require 'orthor/page'
12
+ require 'orthor/static_page'
13
+ require 'orthor/query'
14
+ require 'orthor_helper'
3
15
 
4
- require File.join(File.dirname(__FILE__), 'orthorings')
5
- require File.join(File.dirname(__FILE__), 'orthor_helper')
6
16
  require 'moneta'
17
+ require 'json'
7
18
 
8
19
  class Orthorings
9
20
  require 'net/http'
10
-
21
+
11
22
  class << self
12
23
  dsl_accessor :account_id
13
24
  attr_accessor :cache, :cache_expiry
14
25
 
15
- def content(id)
16
- get_content("content:#{id}", "http://content.orthor.com/#{@account_id}/content_items/#{id}.html")
26
+ def content(id, template = nil)
27
+ render(:content_items, id, template)
17
28
  end
18
-
19
- def query(id)
20
- get_content("query#{id}", "http://content.orthor.com/#{@account_id}/queries/#{id}.html")
29
+
30
+ def query(id, template = nil)
31
+ render(:queries, id, template)
21
32
  end
22
-
23
- def category(id)
24
- get_content("category#{id}", "http://content.orthor.com/#{@account_id}/categories/#{id}.html")
33
+
34
+ def category(id, template = nil)
35
+ render(:categories, id, template)
25
36
  end
26
-
37
+
27
38
  def feed(id)
28
- get_content("feed#{id}", "http://content.orthor.com/#{@account_id}/feeds/#{id}.rss")
39
+ render(:feeds, id)
29
40
  end
30
-
41
+
31
42
  def caching(file, expiry = 300, options = {})
32
43
  klass = file.to_s.split('_').collect { |e| e.capitalize }.join
33
44
  Moneta.autoload(klass.to_sym, "moneta/#{file}")
@@ -36,7 +47,7 @@ class Orthorings
36
47
  end
37
48
 
38
49
  def setup(&block)
39
- raise "Block required" unless block_given?
50
+ raise ArgumentError unless block_given?
40
51
  @cache = false # default
41
52
 
42
53
  class_eval &block
@@ -44,7 +55,7 @@ class Orthorings
44
55
  raise "No orthor account id given... Please add one to your Orthorings setup block" if Orthorings.account_id.nil?
45
56
  ActionView::Base.send(:include, OrthorHelper) if defined?(ActionView::Base) && !ActionView::Base.include?(OrthorHelper)
46
57
  end
47
-
58
+
48
59
  private
49
60
  def get_content(id, url)
50
61
  if @cache
@@ -53,7 +64,7 @@ class Orthorings
53
64
  get_response(url)
54
65
  end
55
66
  end
56
-
67
+
57
68
  def get_cached_content(id, url)
58
69
  content = @cache[id]
59
70
  if content.empty?
@@ -62,17 +73,54 @@ class Orthorings
62
73
  end
63
74
  content
64
75
  end
65
-
76
+
66
77
  def cache_content(id, content)
67
78
  @cache.store(id, content, :expires_in => @cache_expiry) unless content.empty?
68
79
  end
69
-
80
+
70
81
  def get_response(uri)
71
82
  r = Net::HTTP.get_response(URI.parse(uri))
72
- return (r.code.to_i == 200) ? r.body : ""
73
- rescue
74
- return ""
83
+ r.code.to_i == 200 ? r.body : ""
84
+ rescue => e
85
+ ""
86
+ end
87
+
88
+ def render(type, id, template = nil)
89
+ suffix = type == :feeds ? "rss" : "json"
90
+ resp = get_content(id, "http://content.orthor.com/#{@account_id}/#{type}/#{id}.#{suffix}")
91
+
92
+ return resp unless suffix == "json"
93
+
94
+ begin
95
+ json = JSON.parse(resp)
96
+
97
+ template = Orthor::Templates[template]
98
+ return json unless template
99
+
100
+ # ensure we're dealing with an array
101
+ unless json.is_a?(Array)
102
+ if json["type"] == "category"
103
+ json = json["content"]
104
+ else
105
+ json = [json]
106
+ end
107
+ end
108
+ json.collect do |c|
109
+ c.inject(template) do |html, (key, val)|
110
+ # if val.is_a?(Hash)
111
+ if html.include?("{{#{key}.blurb}}")
112
+ val = "#{val.to_s.gsub(/<\/?[^>]*>/, "")[0..150]}..."
113
+ key = "#{key}.blurb"
114
+ end
115
+
116
+ html = html.gsub("{{#{key}}}", val.to_s)
117
+ end
118
+ end.join("")
119
+ rescue => e
120
+ return ""
121
+ end
75
122
  end
76
123
  end
77
124
  end
78
125
 
126
+