citygrid_api 0.0.5 → 0.0.5.1

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.
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