representative_view 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
4
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in representative_view.gemspec
4
+ gemspec
5
+
6
+ group :test do
7
+ gem "rake"
8
+ gem "rspec", "~> 2.0.1"
9
+ gem "rr", "~> 1.0.0"
10
+ gem "minstrel"
11
+ end
data/README.markdown ADDED
@@ -0,0 +1,57 @@
1
+ Representative View
2
+ ===================
3
+
4
+ "Representative View" integrates [Representative](http://github.com/mdub/representative) as a Rails template format, making it possible to generate XML and JSON representations of data <u>using the same template</u>.
5
+
6
+ Installing it
7
+ -------------
8
+
9
+ Simply add the '`representative_view`' gem to your `Gemfile`
10
+
11
+ gem "representative_view"
12
+
13
+ and run "`bundle install`".
14
+
15
+ Using it
16
+ --------
17
+
18
+ In your controller, declare that you can provide both XML and JSON, e.g.
19
+
20
+ class BooksController < ApplicationController
21
+
22
+ def index
23
+ respond_to do |format|
24
+ format.xml
25
+ format.json
26
+ end
27
+ end
28
+
29
+ end
30
+
31
+ Next, create a template with the suffix "`.rep`" (to select the Representative View template handler) and use the Representative DSL to generate elements and lists, e.g.
32
+
33
+ # app/views/books/index.rep
34
+
35
+ r.list_of :books, @books do
36
+ r.element :title
37
+ r.list_of :authors
38
+ end
39
+
40
+ Note that it's "`index.rep`", not "`index.xml.rep`" or "`index.json.rep`"; by omitting the format specifier, the template will be used to render both formats.
41
+
42
+ ### Partials
43
+
44
+ Representative View happily supports the use of partials, as long as they're also in Representative format. Because Representative keeps track of the current "subject" as it renders, there's no need to explicitly pass an object into the partial:
45
+
46
+ # app/views/books/index.rep
47
+
48
+ r.list_of :books, @books do
49
+ render :partial => 'book'
50
+ end
51
+
52
+ # app/views/books/_book.rep
53
+
54
+ r.element :title
55
+ r.element :published do
56
+ r.element :by
57
+ end
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require "rspec/core/rake_task"
5
+
6
+ task "default" => "spec"
7
+
8
+ RSpec::Core::RakeTask.new do |t|
9
+ t.pattern = 'spec/**/*_spec.rb'
10
+ t.rspec_opts = ["--colour", "--format", "nested"]
11
+ end
@@ -0,0 +1 @@
1
+ require 'representative_view/template_handler'
@@ -0,0 +1,60 @@
1
+ require 'action_view'
2
+
3
+ module RepresentativeView
4
+
5
+ class TemplateHandler < ActionView::Template::Handler
6
+
7
+ include ActionView::Template::Handlers::Compilable
8
+
9
+ self.default_format = Mime::XML
10
+
11
+ def compile(template)
12
+ require 'representative/json'
13
+ require 'representative/nokogiri'
14
+ <<-RUBY
15
+ representative_view do |r|
16
+ #{template.source}
17
+ end
18
+ RUBY
19
+ end
20
+
21
+ end
22
+
23
+ module ViewHelpers
24
+
25
+ def mime_type
26
+ format_extension = formats.first
27
+ Mime::Type.lookup_by_extension(format_extension.to_s) || begin
28
+ raise "unrecognised format #{format_extension.inspect}"
29
+ end
30
+ end
31
+
32
+ def appropriate_representative_class
33
+ case mime_type.to_s
34
+ when /xml/
35
+ ::Representative::Nokogiri
36
+ when /json/
37
+ ::Representative::JSON
38
+ else
39
+ raise "cannot determine appropriate Representative class for #{mime_type.to_s.inspect}"
40
+ end
41
+ end
42
+
43
+ def representative_view
44
+ included = defined?(@_representative)
45
+ @_representative ||= appropriate_representative_class.new
46
+ yield @_representative
47
+ @_representative.to_s unless included
48
+ end
49
+
50
+ end
51
+
52
+ end
53
+
54
+ ActionView::Template.register_template_handler(:rep, RepresentativeView::TemplateHandler)
55
+
56
+ class ActionView::Base
57
+
58
+ include RepresentativeView::ViewHelpers
59
+
60
+ end
@@ -0,0 +1,3 @@
1
+ module RepresentativeView
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "representative_view/version"
4
+
5
+ Gem::Specification.new do |gem|
6
+
7
+ gem.name = "representative_view"
8
+ gem.summary = "Builds XML and JSON from a single view template"
9
+ gem.homepage = "http://github.com/mdub/representative_view"
10
+ gem.authors = ["Mike Williams"]
11
+ gem.email = "mdub@dogbiscuit.org"
12
+
13
+ gem.version = RepresentativeView::VERSION.dup
14
+ gem.platform = Gem::Platform::RUBY
15
+
16
+ gem.add_runtime_dependency("representative", "~> 0.3.1")
17
+ gem.add_runtime_dependency("actionpack", "~> 3.0.1")
18
+ gem.add_runtime_dependency("nokogiri", ">= 1.4.2")
19
+ gem.add_runtime_dependency("json", ">= 1.4.5")
20
+
21
+ gem.require_paths = ["lib"]
22
+
23
+ gem.files = `git ls-files`.split("\n")
24
+ gem.test_files = `git ls-files -- spec/*`.split("\n")
25
+
26
+ end
@@ -0,0 +1,31 @@
1
+ module Books
2
+
3
+ def all
4
+ [
5
+ OpenStruct.new(
6
+ :title => "Sailing for old dogs",
7
+ :authors => ["Jim Watson"],
8
+ :published => OpenStruct.new(
9
+ :by => "Credulous Print",
10
+ :year => 1994
11
+ )
12
+ ),
13
+ OpenStruct.new(
14
+ :title => "On the horizon",
15
+ :authors => ["Zoe Primpton", "Stan Ford"],
16
+ :published => OpenStruct.new(
17
+ :by => "McGraw-Hill",
18
+ :year => 2005
19
+ )
20
+ ),
21
+ OpenStruct.new(
22
+ :title => "The Little Blue Book of VHS Programming",
23
+ :authors => ["Henry Nelson"],
24
+ :rating => "****"
25
+ )
26
+ ]
27
+ end
28
+
29
+ extend self
30
+
31
+ end
@@ -0,0 +1,103 @@
1
+ require 'spec_helper'
2
+
3
+ describe "a Representative template" do
4
+
5
+ before do
6
+ write_template 'books.rep', <<-RUBY
7
+ r.list_of :books, @books do
8
+ r.element :title
9
+ end
10
+ RUBY
11
+ end
12
+
13
+ it "can generate XML" do
14
+ render("books", :xml, :books => Books.all).should == undent(<<-XML)
15
+ <?xml version="1.0"?>
16
+ <books type="array">
17
+ <book>
18
+ <title>Sailing for old dogs</title>
19
+ </book>
20
+ <book>
21
+ <title>On the horizon</title>
22
+ </book>
23
+ <book>
24
+ <title>The Little Blue Book of VHS Programming</title>
25
+ </book>
26
+ </books>
27
+ XML
28
+ end
29
+
30
+ it "can generate XML dialects" do
31
+ Mime::Type.register "application/vnd.books+xml", :book_xml
32
+ render("books", :book_xml, :books => Books.all).should == undent(<<-XML)
33
+ <?xml version="1.0"?>
34
+ <books type="array">
35
+ <book>
36
+ <title>Sailing for old dogs</title>
37
+ </book>
38
+ <book>
39
+ <title>On the horizon</title>
40
+ </book>
41
+ <book>
42
+ <title>The Little Blue Book of VHS Programming</title>
43
+ </book>
44
+ </books>
45
+ XML
46
+ end
47
+
48
+ it "can generate JSON" do
49
+ render("books", :json, :books => Books.all).should == undent(<<-JSON)
50
+ [
51
+ {
52
+ "title": "Sailing for old dogs"
53
+ },
54
+ {
55
+ "title": "On the horizon"
56
+ },
57
+ {
58
+ "title": "The Little Blue Book of VHS Programming"
59
+ }
60
+ ]
61
+ JSON
62
+ end
63
+
64
+ it "can include partials" do
65
+
66
+ write_template 'books_with_partial.rep', <<-RUBY
67
+ r.list_of :books, @books do
68
+ render :partial => 'book'
69
+ end
70
+ RUBY
71
+
72
+ write_template '_book.rep', <<-RUBY
73
+ r.element :title
74
+ r.element :published do
75
+ r.element :by
76
+ end
77
+ RUBY
78
+
79
+ render("books_with_partial", :json, :books => Books.all).should == undent(<<-JSON)
80
+ [
81
+ {
82
+ "title": "Sailing for old dogs",
83
+ "published": {
84
+ "by": "Credulous Print"
85
+ }
86
+ },
87
+ {
88
+ "title": "On the horizon",
89
+ "published": {
90
+ "by": "McGraw-Hill"
91
+ }
92
+ },
93
+ {
94
+ "title": "The Little Blue Book of VHS Programming",
95
+ "published": null
96
+ }
97
+ ]
98
+ JSON
99
+
100
+ end
101
+
102
+
103
+ end
@@ -0,0 +1,52 @@
1
+ require 'action_view'
2
+ require 'minstrel'
3
+ require 'representative_view'
4
+ require 'rspec'
5
+
6
+ require 'pathname'
7
+ require 'fixtures/books'
8
+
9
+ $tmp_dir = Pathname(__FILE__).parent.parent + "tmp"
10
+ $template_dir = $tmp_dir + "templates"
11
+
12
+ module Fixtures
13
+
14
+ def write_template(name, content)
15
+ template_path = $template_dir + name
16
+ template_path.parent.mkpath
17
+ template_path.open("w") do |io|
18
+ io << content
19
+ end
20
+ end
21
+
22
+ def render(file, format = :xml, assigns = {})
23
+ @base = ActionView::Base.new($template_dir.to_str, assigns)
24
+ @base.lookup_context.freeze_formats([format])
25
+ @base.render(:file => file)
26
+ end
27
+
28
+ end
29
+
30
+ Rspec.configure do |config|
31
+
32
+ config.mock_with :rr
33
+ config.include(Fixtures)
34
+
35
+ config.before do
36
+ $template_dir.mkpath
37
+ end
38
+
39
+ config.after do
40
+ $tmp_dir.rmtree if $tmp_dir.exist?
41
+ end
42
+
43
+ end
44
+
45
+ def undent(raw)
46
+ if raw =~ /\A( +)/
47
+ indent = $1
48
+ raw.gsub(/^#{indent}/, '').gsub(/ +$/, '')
49
+ else
50
+ raw
51
+ end
52
+ end
metadata ADDED
@@ -0,0 +1,142 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: representative_view
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Mike Williams
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-02-10 00:00:00 +11:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ version_requirements: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ~>
26
+ - !ruby/object:Gem::Version
27
+ hash: 17
28
+ segments:
29
+ - 0
30
+ - 3
31
+ - 1
32
+ version: 0.3.1
33
+ prerelease: false
34
+ type: :runtime
35
+ requirement: *id001
36
+ name: representative
37
+ - !ruby/object:Gem::Dependency
38
+ version_requirements: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ hash: 5
44
+ segments:
45
+ - 3
46
+ - 0
47
+ - 1
48
+ version: 3.0.1
49
+ prerelease: false
50
+ type: :runtime
51
+ requirement: *id002
52
+ name: actionpack
53
+ - !ruby/object:Gem::Dependency
54
+ version_requirements: &id003 !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ hash: 3
60
+ segments:
61
+ - 1
62
+ - 4
63
+ - 2
64
+ version: 1.4.2
65
+ prerelease: false
66
+ type: :runtime
67
+ requirement: *id003
68
+ name: nokogiri
69
+ - !ruby/object:Gem::Dependency
70
+ version_requirements: &id004 !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ hash: 13
76
+ segments:
77
+ - 1
78
+ - 4
79
+ - 5
80
+ version: 1.4.5
81
+ prerelease: false
82
+ type: :runtime
83
+ requirement: *id004
84
+ name: json
85
+ description:
86
+ email: mdub@dogbiscuit.org
87
+ executables: []
88
+
89
+ extensions: []
90
+
91
+ extra_rdoc_files: []
92
+
93
+ files:
94
+ - .gitignore
95
+ - Gemfile
96
+ - README.markdown
97
+ - Rakefile
98
+ - lib/representative_view.rb
99
+ - lib/representative_view/template_handler.rb
100
+ - lib/representative_view/version.rb
101
+ - representative_view.gemspec
102
+ - spec/fixtures/books.rb
103
+ - spec/representative_view/template_handler_spec.rb
104
+ - spec/spec_helper.rb
105
+ has_rdoc: true
106
+ homepage: http://github.com/mdub/representative_view
107
+ licenses: []
108
+
109
+ post_install_message:
110
+ rdoc_options: []
111
+
112
+ require_paths:
113
+ - lib
114
+ required_ruby_version: !ruby/object:Gem::Requirement
115
+ none: false
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ hash: 3
120
+ segments:
121
+ - 0
122
+ version: "0"
123
+ required_rubygems_version: !ruby/object:Gem::Requirement
124
+ none: false
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ hash: 3
129
+ segments:
130
+ - 0
131
+ version: "0"
132
+ requirements: []
133
+
134
+ rubyforge_project:
135
+ rubygems_version: 1.5.0
136
+ signing_key:
137
+ specification_version: 3
138
+ summary: Builds XML and JSON from a single view template
139
+ test_files:
140
+ - spec/fixtures/books.rb
141
+ - spec/representative_view/template_handler_spec.rb
142
+ - spec/spec_helper.rb