citygrid_api 0.0.5 → 0.0.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. data/.sass-cache/7a5a675d951455410512a59af5ab2d160bd1735c/test.scssc +0 -0
  2. data/Gemfile +10 -8
  3. data/Gemfile.lock +24 -9
  4. data/README +21 -0
  5. data/citygrid_api.gemspec +77 -17
  6. data/citygrid_api.yml.sample +33 -0
  7. data/config.ru +2 -0
  8. data/dashboard.rb +110 -0
  9. data/lib/citygrid/abstraction/collection.rb +1 -1
  10. data/lib/citygrid/abstraction/super_hash.rb +2 -0
  11. data/lib/citygrid/api/ad_center/account.rb +26 -0
  12. data/lib/citygrid/api/ad_center/account_manager.rb +8 -0
  13. data/lib/citygrid/api/ad_center/ad_group.rb +8 -0
  14. data/lib/citygrid/api/ad_center/ad_group_ad.rb +8 -0
  15. data/lib/citygrid/api/ad_center/ad_group_criterion.rb +8 -0
  16. data/lib/citygrid/api/ad_center/ad_group_geo.rb +8 -0
  17. data/lib/citygrid/api/ad_center/authentication.rb +20 -0
  18. data/lib/citygrid/api/ad_center/billing.rb +8 -0
  19. data/lib/citygrid/api/ad_center/budget.rb +9 -0
  20. data/lib/citygrid/api/ad_center/call_detail.rb +25 -0
  21. data/lib/citygrid/api/ad_center/campaign.rb +8 -0
  22. data/lib/citygrid/api/ad_center/category.rb +9 -0
  23. data/lib/citygrid/api/ad_center/geolocation.rb +9 -0
  24. data/lib/citygrid/api/ad_center/image.rb +30 -0
  25. data/lib/citygrid/api/ad_center/method_of_payment.rb +10 -0
  26. data/lib/citygrid/api/ad_center/performance.rb +17 -0
  27. data/lib/citygrid/api/ad_center/places.rb +8 -0
  28. data/lib/citygrid/api/ad_center/user.rb +8 -0
  29. data/lib/citygrid/api/ad_center.rb +20 -0
  30. data/lib/citygrid/api/content/offers.rb +14 -9
  31. data/lib/citygrid/api/content/places/detail.rb +5 -11
  32. data/lib/citygrid/api/content/places/search.rb +5 -11
  33. data/lib/citygrid/api/content/places.rb +30 -14
  34. data/lib/citygrid/api/content/reviews.rb +5 -10
  35. data/lib/citygrid/api/content.rb +12 -3
  36. data/lib/citygrid/api/response.rb +2 -2
  37. data/lib/citygrid/api.rb +190 -3
  38. data/lib/citygrid/details.rb +1 -1
  39. data/lib/citygrid/listing.rb +7 -2
  40. data/lib/citygrid/offers.rb +4 -0
  41. data/lib/citygrid/reviews.rb +4 -0
  42. data/lib/citygrid/search.rb +6 -0
  43. data/lib/citygrid.rb +117 -12
  44. data/lib/dashboard/sinatra_partial.rb +17 -0
  45. data/lib/dashboard/stored_reporter.rb +101 -0
  46. data/lib/dashboard/test_result.rb +8 -0
  47. data/lib/request_ext.rb +32 -0
  48. data/public/javascript/dashboard.js +5 -0
  49. data/test/api/ad_center/test_account.rb +120 -0
  50. data/test/api/ad_center/test_ad_group.rb +50 -0
  51. data/test/api/ad_center/test_ad_group_ad.rb +27 -0
  52. data/test/api/ad_center/test_ad_group_criterion.rb +37 -0
  53. data/test/api/ad_center/test_ad_group_geo.rb +19 -0
  54. data/test/api/ad_center/test_authentication.rb +22 -0
  55. data/test/api/ad_center/test_billing.rb +14 -0
  56. data/test/api/ad_center/test_budget.rb +13 -0
  57. data/test/api/ad_center/test_call_detail.rb +36 -0
  58. data/test/api/ad_center/test_campaign.rb +27 -0
  59. data/test/api/ad_center/test_category.rb +37 -0
  60. data/test/api/ad_center/test_geolocation.rb +19 -0
  61. data/test/api/ad_center/test_image.rb +17 -0
  62. data/test/api/ad_center/test_method_of_payment.rb +51 -0
  63. data/test/api/ad_center/test_places.rb +79 -0
  64. data/test/api/ad_center/test_reports.rb +37 -0
  65. data/test/api/content/test_offers.rb +28 -0
  66. data/test/api/content/test_places.rb +66 -0
  67. data/test/helper.rb +67 -14
  68. data/test/test_config.rb +11 -0
  69. data/test/test_details.rb +14 -5
  70. data/test/test_img.jpg +0 -0
  71. data/test/test_img_big.png +0 -0
  72. data/test/test_listing.rb +64 -64
  73. data/test/test_search.rb +21 -1
  74. data/test/test_super_array.rb +1 -1
  75. data/test/test_super_hash.rb +1 -1
  76. data/views/_context_result.haml +25 -0
  77. data/views/_request.haml +3 -0
  78. data/views/_test_result.haml +4 -0
  79. data/views/stylesheets/test.scss +53 -0
  80. data/views/test.haml +8 -0
  81. metadata +145 -114
  82. data/lib/citygrid/api/base.rb +0 -60
  83. data/test/test_citygrid.rb +0 -7
@@ -0,0 +1,8 @@
1
+ class CityGrid
2
+ class API
3
+ class AdCenter
4
+ class User < AdCenter
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,20 @@
1
+ class CityGrid
2
+ class API
3
+ class AdCenter < API
4
+ server :default
5
+ def self.initialize
6
+ puts "init adCenter"
7
+ end
8
+ end
9
+ end
10
+ end
11
+
12
+ [
13
+ "account", "account_manager", "ad_group", "ad_group_ad", "ad_group_criterion", "ad_group_geo",
14
+ "authentication", "budget", "campaign", "category", "geolocation", "method_of_payment", "places", "performance",
15
+ "image", "user", "call_detail", "billing"
16
+ ].each do |x|
17
+ require "citygrid/api/ad_center/#{x}"
18
+ end
19
+
20
+
@@ -1,13 +1,18 @@
1
1
  class CityGrid
2
- module API
3
- module Content
4
- module Offers
5
- include CityGrid::API::Base
6
-
7
- class << self
8
- def endpoint
9
- "/offers/v2/search/places"
10
- end
2
+ class API
3
+ class Content
4
+ class Offers < Content
5
+ @base_endpoint = "http://api.citygridmedia.com/content/offers/v2/search"
6
+ endpoint @base_endpoint
7
+
8
+ def self.where options = {}
9
+ endpoint "#{@base_endpoint}/where"
10
+ request_with_publisher options
11
+ end
12
+
13
+ def self.places options = {}
14
+ endpoint "#{@base_endpoint}/places"
15
+ request_with_publisher options
11
16
  end
12
17
  end
13
18
  end
@@ -1,15 +1,9 @@
1
1
  class CityGrid
2
- module API
3
- module Content
4
- module Places
5
- module Detail
6
- include CityGrid::API::Base
7
-
8
- class << self
9
- def endpoint
10
- "/places/v2/detail"
11
- end
12
- end
2
+ class API
3
+ class Content
4
+ class Places
5
+ class Detail < Places
6
+ endpoint "/content/places/v2/detail"
13
7
  end
14
8
  end
15
9
  end
@@ -1,15 +1,9 @@
1
1
  class CityGrid
2
- module API
3
- module Content
4
- module Places
5
- module Search
6
- include CityGrid::API::Base
7
-
8
- class << self
9
- def endpoint
10
- "/places/v2/search/where"
11
- end
12
- end
2
+ class API
3
+ class Content
4
+ class Places
5
+ class Search < Places
6
+ endpoint "/content/places/v2/search/where"
13
7
  end
14
8
  end
15
9
  end
@@ -1,20 +1,36 @@
1
- require "citygrid/api/content/places/detail"
2
- require "citygrid/api/content/places/search"
3
-
4
1
  class CityGrid
5
- module API
6
- module Content
7
- module Places
8
- extend self
9
-
10
- def detail opts
11
- Detail.request opts
12
- end
2
+ class API
3
+ class Content
4
+ class Places < Content
5
+ base_uri "api.citygridmedia.com"
6
+ endpoint "/content/places/v2"
7
+
8
+ class << self
9
+ def detail opts
10
+ Detail.request opts
11
+ end
13
12
 
14
- def search opts
15
- Search.request opts
13
+ def search opts
14
+ Search.request opts
15
+ end
16
+
17
+ def mutate options = {}
18
+ token = extract_auth_token options
19
+ request_and_handle :post,
20
+ "#{endpoint}/mutate",
21
+ :body => options.to_json,
22
+ :headers => merge_headers("authToken" => token)
23
+ end
24
+
16
25
  end
17
26
  end
18
27
  end
19
28
  end
20
- end
29
+ end
30
+
31
+ [
32
+ "detail", "search"
33
+ ].each do |x|
34
+ require "citygrid/api/content/places/#{x}"
35
+ end
36
+
@@ -1,14 +1,9 @@
1
1
  class CityGrid
2
- module API
3
- module Content
4
- module Reviews
5
- include CityGrid::API::Base
6
-
7
- class << self
8
- def endpoint
9
- "/reviews/v2/search/where"
10
- end
11
- end
2
+ class API
3
+ class Content
4
+ class Reviews < Content
5
+ base_uri "api.citygridmedia.com"
6
+ endpoint "/content/reviews/v2/search/where"
12
7
  end
13
8
  end
14
9
  end
@@ -1,3 +1,12 @@
1
- require "citygrid/api/content/offers"
2
- require "citygrid/api/content/places"
3
- require "citygrid/api/content/reviews"
1
+ class CityGrid
2
+ class API
3
+ class Content < API
4
+ end
5
+ end
6
+ end
7
+
8
+ [
9
+ "offers", "places", "reviews"
10
+ ].each do |x|
11
+ require "citygrid/api/content/#{x}"
12
+ end
@@ -1,11 +1,11 @@
1
1
  class CityGrid
2
- module API
2
+ class API
3
3
  # Creates SuperHash from parsed_response
4
4
  # Stores response object in @response.
5
5
  # ------------------------------------ #
6
6
  class Response < CityGrid::Abstraction::SuperHash
7
7
  attr_reader :httparty
8
-
8
+
9
9
  def self.new httparty_response
10
10
  resp = super httparty_response.parsed_response
11
11
  resp.instance_variable_set "@httparty", httparty_response
data/lib/citygrid/api.rb CHANGED
@@ -1,3 +1,190 @@
1
- %w{base response content}.each do |api|
2
- require "citygrid/api/#{api}"
3
- end
1
+ require "httparty"
2
+ require "json"
3
+
4
+ class CityGrid
5
+ class API
6
+ include HTTParty
7
+ format :json
8
+ #debug_output $stderr
9
+
10
+ class << self
11
+ # server setting - :default or :ssl
12
+ def server val=nil
13
+ return @server || (superclass.respond_to?(:server) ? superclass.server : nil) unless val
14
+ @server = val
15
+ end
16
+
17
+ def hostname val=nil
18
+ return @hostname || (superclass.respond_to?(:hostname) ? superclass.hostname : nil) unless val
19
+ @hostname = val
20
+ end
21
+
22
+ def endpoint val=nil
23
+ return @endpoint unless val
24
+ @endpoint = val
25
+ end
26
+
27
+ def publisher
28
+ CityGrid.publisher
29
+ end
30
+
31
+ def request options = {}
32
+ method = (options.delete(:method) || :get).to_sym
33
+ query = options.merge :format => :json
34
+ request_and_handle method, endpoint, :query => query
35
+ end
36
+
37
+ def request_with_publisher options = {}
38
+ request options.merge(:publisher => publisher)
39
+ end
40
+
41
+ def mutate options = {}
42
+ token = extract_auth_token options
43
+ request_and_handle :post,
44
+ "#{endpoint}/mutate",
45
+ :body => options.to_json,
46
+ :headers => merge_headers("authToken" => token)
47
+ end
48
+
49
+ def search options = {}
50
+ token = extract_auth_token options
51
+ request_and_handle :get,
52
+ "#{endpoint}/get",
53
+ :query => options,
54
+ :headers => merge_headers("authToken" => token)
55
+ end
56
+
57
+ private
58
+ def extract_auth_token options = {}
59
+ options.delete(:token) #|| raise(MissingAuthToken)
60
+ end
61
+
62
+ def merge_headers options = {}
63
+ {"Accept" => "application/json",
64
+ "Content-Type" => "Application/JSON"}.merge options
65
+ end
66
+
67
+ def convert_to_querystring hash
68
+ hash.map do |k, v|
69
+ key = URI.escape k.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]")
70
+ val = URI.escape v.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]")
71
+ !value.empty? && !key.empty? ? "#{key}=#{value}" : nil
72
+ end.compact.join("&")
73
+ end
74
+
75
+ HTTP_METHODS = {
76
+ "put" => Net::HTTP::Put,
77
+ "get" => Net::HTTP::Get,
78
+ "post" => Net::HTTP::Post,
79
+ "delete" => Net::HTTP::Delete,
80
+ "head" => Net::HTTP::Head,
81
+ "options" => Net::HTTP::Options
82
+ }
83
+
84
+ # Transform response into API::Response object
85
+ # or throw exception if an error exists
86
+ def request_and_handle http_method, path, options
87
+ if http_method.is_a?(String) || http_method.is_a?(Symbol)
88
+ http_method = HTTP_METHODS[http_method.to_s]
89
+ raise "Unknown http method: #{http_method}" unless http_method
90
+ end
91
+
92
+ req_options = default_options.dup
93
+ req_options = req_options.merge({:base_uri => CityGrid.config[server]}) if !base_uri && server
94
+ req_options = req_options.merge(options)
95
+
96
+ req = HTTParty::Request.new http_method, path, req_options
97
+ error = nil
98
+
99
+ begin
100
+ response = req.perform
101
+ rescue => ex
102
+ puts "Something went wrong with Request.perform"
103
+ error = StandardError.new "Internal Error"
104
+ rescue Psych::SyntaxError => ex
105
+ puts "Something went wrong with Request.perform, Psych:SyntaxError"
106
+ error = StandardError.new "Internal Error"
107
+ end
108
+
109
+ if defined?(Rails.logger)
110
+ Rails.logger.info req.to_curl
111
+ else
112
+ puts req.to_curl
113
+ end
114
+
115
+ unless error
116
+ if !response.parsed_response.is_a?(Hash)
117
+ error = InvalidResponseFormat.new response
118
+ elsif response["errors"]
119
+ error = Error.new response["errors"], response
120
+ else
121
+ return CityGrid::API::Response.new response
122
+ end
123
+ end
124
+
125
+ if error
126
+ puts "an error happened"
127
+ puts req.to_json
128
+ #raise error
129
+ end
130
+ end
131
+ end
132
+
133
+ # ERRORS
134
+ class GenericError < StandardError
135
+ attr_reader :httparty, :message
136
+
137
+ def initialize msg, response = nil
138
+ @message = msg
139
+ @httparty = response
140
+ end
141
+ end
142
+
143
+ class Error < GenericError
144
+ def initialize errors, response
145
+ super errors.first["error"], response
146
+ end
147
+ end
148
+
149
+ class InvalidResponseFormat < GenericError
150
+ attr_accessor :server_msg, :description
151
+ def initialize response = nil
152
+ # parse Tomcat error report
153
+ if response.match /<title>Apache Tomcat.* - Error report<\/title>/
154
+ response.scan(/<p><b>(message|description)<\/b> *<u>(.*?)<\/u><\/p>/).each do |match|
155
+ case match[0]
156
+ when "message"
157
+ self.server_msg = match[1]
158
+ when "description"
159
+ self.description = match[1]
160
+ end
161
+ end
162
+
163
+ error_body = response.match(/<body>(.*?)<\/body>/m)[1]
164
+
165
+ msg = <<-EOS
166
+ Unexpected response format. Expected response to be a hash, but was instead:\n#{error_body}\n
167
+ EOS
168
+
169
+ super msg, error_body
170
+ else
171
+ msg = <<-EOS
172
+ Unexpected response format. Expected response to be a hash, but was instead:\n#{response.parsed_response}\n
173
+ EOS
174
+
175
+ super msg, response
176
+ end
177
+ end
178
+ end
179
+
180
+ class MissingAuthToken < GenericError
181
+ def initialize
182
+ super message
183
+ end
184
+
185
+ def message
186
+ "Missing authToken - token is required"
187
+ end
188
+ end
189
+ end
190
+ end
@@ -5,7 +5,7 @@ class CityGrid
5
5
  end
6
6
 
7
7
  def request opts = {}
8
- api.request opts.merge(:client_ip => "192.168.0.1")
8
+ api.request_with_publisher opts.merge(:client_ip => "192.168.0.1")
9
9
  end
10
10
  end
11
11
 
@@ -12,8 +12,13 @@ class CityGrid
12
12
  end
13
13
 
14
14
  def method_missing meth, *args, &block
15
- load unless @loaded
16
- send(meth, *args, &block) rescue super
15
+ if @loaded
16
+ super
17
+ else
18
+ @loaded = true
19
+ load
20
+ send(meth, *args, &block)
21
+ end
17
22
  end
18
23
 
19
24
  private
@@ -4,6 +4,10 @@ class CityGrid
4
4
  CityGrid::API::Content::Offers
5
5
  end
6
6
 
7
+ def request opts = {}
8
+ api.request_with_publisher opts
9
+ end
10
+
7
11
  private
8
12
 
9
13
  def preprocess response
@@ -4,6 +4,10 @@ class CityGrid
4
4
  CityGrid::API::Content::Reviews
5
5
  end
6
6
 
7
+ def request opts = {}
8
+ api.request_with_publisher opts
9
+ end
10
+
7
11
  def total_hits
8
12
  raw["results"]["total_hits"]
9
13
  end
@@ -4,9 +4,15 @@ class CityGrid
4
4
  CityGrid::API::Content::Places::Search
5
5
  end
6
6
 
7
+ def request opts = {}
8
+ api.request_with_publisher opts
9
+ end
10
+
7
11
  private
8
12
 
9
13
  def preprocess response
14
+ return nil unless response && response.results && response.results.locations
15
+
10
16
  response.results.locations.map do |attrs|
11
17
  Listing.new attrs
12
18
  end
data/lib/citygrid.rb CHANGED
@@ -1,21 +1,16 @@
1
- require "citygrid/abstraction"
2
- require "citygrid/api"
3
-
4
- require "citygrid/search"
5
- require "citygrid/reviews"
6
- require "citygrid/offers"
7
- require "citygrid/details"
8
- require "citygrid/listing"
1
+ # Ruby 1.9.2 has YAML::ENGINE and will blow up if you don't define yamler
2
+ # Ruby 1.8.7 doesn't have YAML::ENGINE, this should take care of both cases
3
+ YAML::ENGINE.yamler= 'syck' if defined?(YAML::ENGINE)
9
4
 
10
5
  class CityGrid
11
6
  class << self
12
7
  def publisher= code
13
- @@publisher = code
8
+ @publisher = code
14
9
  end
15
-
10
+
16
11
  def publisher
17
- raise PublisherNotConfigured if !defined?(@@publisher) || @@publisher.nil?
18
- @@publisher
12
+ raise PublisherNotConfigured if !defined?(@publisher) || @publisher.nil?
13
+ @publisher
19
14
  end
20
15
 
21
16
  def search opts = {}
@@ -33,6 +28,72 @@ class CityGrid
33
28
  def reviews opts
34
29
  Reviews.new opts
35
30
  end
31
+
32
+ def authenticate params
33
+ API::AdCenter::Authentication.login params
34
+ end
35
+ alias_method :login, :authenticate
36
+
37
+ # config info
38
+ def load_config file_path, env = nil
39
+ config = YAML.load_file(file_path)
40
+
41
+ defaults = config["defaults"]
42
+
43
+ default_hostname = "http://#{defaults["hostname"]}"
44
+ ssl_hostname = "https://#{defaults["ssl_hostname"]}"
45
+
46
+ config["endpoints"].each do |k, v|
47
+ # camelcase classname
48
+ classname = k.gsub(/(_(.))/) { $2.upcase}.gsub(/^(.)/) { $1.upcase }
49
+ klass = API::AdCenter.const_get(classname)
50
+ if v.is_a? String
51
+ endpoint = v.start_with?("/") ? v : "/#{v}"
52
+ klass.endpoint endpoint
53
+ klass.base_uri default_hostname
54
+ elsif v.is_a? Hash
55
+ hostname = v["hostname"] || (v["ssl"] ? ssl_hostname : default_hostname)
56
+
57
+ endpoint = v["endpoint"].start_with?("/") ? v["endpoint"] : "/#{v["endpoint"]}"
58
+ klass.endpoint endpoint
59
+ klass.base_uri hostname
60
+ else
61
+ # should not get here
62
+ end
63
+ end
64
+ end
65
+
66
+ def config
67
+ raise EndpointsNotConfigured unless @config && !@config.nil?
68
+ @config
69
+ end
70
+
71
+ def set_endpoints config_file
72
+ File.open config_file, "r" do |file|
73
+ while line = file.gets
74
+ api, endpoint = line.split("=").map{|x| x.chomp}
75
+ endpoint = "/#{endpoint}" unless endpoint.start_with?("/")
76
+ klass = CLASS_MAPPING[api]
77
+ next unless klass
78
+
79
+ klass.endpoint endpoint
80
+ end
81
+ end
82
+ end
83
+
84
+ def set_env config_file
85
+ File.open config_file, "r" do |file|
86
+ while line = file.gets
87
+ api, host = line.split("=").map{|x| x.chomp}
88
+ host = "http://#{host}" unless host.start_with?("http")
89
+ klass = CLASS_MAPPING[api]
90
+ next unless klass
91
+
92
+ klass.base_uri host
93
+ end
94
+ end
95
+ end
96
+
36
97
  end
37
98
 
38
99
  # Errors
@@ -42,4 +103,48 @@ class CityGrid
42
103
  super "Publisher hasn't been configured. Run 'CityGrid.publisher=<code>'"
43
104
  end
44
105
  end
106
+
107
+ class EndpointsNotConfigured < StandardError
108
+ def initialize
109
+ super "Endpoints haven't been configured. Run 'CityGrid.load_config'"
110
+ end
111
+ end
112
+ end
113
+
114
+ require "citygrid/abstraction"
115
+ require "citygrid/api"
116
+
117
+ require "citygrid/search"
118
+ require "citygrid/reviews"
119
+ require "citygrid/offers"
120
+ require "citygrid/details"
121
+ require "citygrid/listing"
122
+
123
+ require "citygrid/api/response"
124
+ require "citygrid/api/ad_center"
125
+ require "citygrid/api/content"
126
+
127
+ require "request_ext"
128
+
129
+ class CityGrid
130
+ CLASS_MAPPING = {
131
+ "account" => CityGrid::API::AdCenter::Account,
132
+ "accountmanager" => CityGrid::API::AdCenter::AccountManager,
133
+ "adgroup" => CityGrid::API::AdCenter::AdGroup,
134
+ "adgroupad" => CityGrid::API::AdCenter::AdGroupAd,
135
+ "adgroupgeo" => CityGrid::API::AdCenter::AdGroupGeo,
136
+ "billing" => CityGrid::API::AdCenter::Billing,
137
+ "adgroupcriterion" => CityGrid::API::AdCenter::AdGroupCriterion,
138
+ "authentication" => CityGrid::API::AdCenter::Authentication,
139
+ "budget" => CityGrid::API::AdCenter::Budget,
140
+ "campaign" => CityGrid::API::AdCenter::Campaign,
141
+ "category" => CityGrid::API::AdCenter::Category,
142
+ "geolocation" => CityGrid::API::AdCenter::GeoLocation,
143
+ "mop" => CityGrid::API::AdCenter::MethodOfPayment,
144
+ "image" => CityGrid::API::AdCenter::Image,
145
+ "places" => CityGrid::API::AdCenter::Places,
146
+ "performance" => CityGrid::API::AdCenter::Performance,
147
+ # "reviews" => CityGrid::API::AdCenter::Reviews
148
+ "user" => CityGrid::API::AdCenter::User
149
+ }
45
150
  end
@@ -0,0 +1,17 @@
1
+ module Sinatra::Partials
2
+ def partial(template, *args)
3
+ template_array = template.to_s.split('/')
4
+ template = template_array[0..-2].join('/') + "/_#{template_array[-1]}"
5
+ options = args.last.is_a?(Hash) ? args.pop : {}
6
+ options.merge!(:layout => false)
7
+ if collection = options.delete(:collection) then
8
+ collection.inject([]) do |buffer, member|
9
+ buffer << haml(:"#{template}", options.merge(:layout =>
10
+ false, :locals => {template_array[-1].to_sym => member}))
11
+
12
+ end.join("\n")
13
+ else
14
+ haml(:"#{template}", options)
15
+ end
16
+ end
17
+ end