Class: Nested::Resource
- Inherits:
-
Object
- Object
- Nested::Resource
- Defined in:
- lib/nested.rb
Constant Summary collapse
- FETCH =
-> do raise "implement fetch for resource #{@__resource.name}" unless @__resource.parent raise "implement fetch for singleton #{@__resource.name}" if @__resource.singleton? parent_resource = @__resource.parent parent_obj = instance_variable_get("@#{parent_resource.instance_variable_name}") if @__resource.name scope = parent_obj.send(@__resource.name.to_s.pluralize.to_sym) @__resource.collection? ? scope : scope.where(id: params["#{@__resource.name.to_s.singularize}_id"]).first else parent_obj.where(id: params["#{parent_resource.name.to_s.singularize}_id"]).first end end
Instance Attribute Summary collapse
-
#actions ⇒ Object
readonly
Returns the value of attribute actions.
-
#name ⇒ Object
readonly
Returns the value of attribute name.
-
#parent ⇒ Object
readonly
Returns the value of attribute parent.
-
#resources ⇒ Object
readonly
Returns the value of attribute resources.
Instance Method Summary collapse
- #child_resource(name, singleton, collection, init_block, &block) ⇒ Object
- #collection? ⇒ Boolean
- #create_sinatra_route(method, action, &block) ⇒ Object
- #delete(action = nil, &block) ⇒ Object
- #get(action = nil, &block) ⇒ Object
- #init(&block) ⇒ Object
-
#initialize(sinatra, name, singleton, collection, parent, init_block) ⇒ Resource
constructor
A new instance of Resource.
- #instance_variable_name ⇒ Object
- #many(name, init_block = nil, &block) ⇒ Object
- #member? ⇒ Boolean
- #one(name = nil, init_block = nil, &block) ⇒ Object
- #parents ⇒ Object
- #post(action = nil, &block) ⇒ Object
- #put(action = nil, &block) ⇒ Object
- #route(args = {}, action = nil) ⇒ Object
- #self_and_parents ⇒ Object
- #serialize(*args, &block) ⇒ Object
- #sinatra_exec_delete_block(sinatra, &block) ⇒ Object
- #sinatra_exec_get_block(sinatra, &block) ⇒ Object
- #sinatra_exec_post_block(sinatra, &block) ⇒ Object
- #sinatra_exec_put_block(sinatra, &block) ⇒ Object
- #sinatra_init(sinatra) ⇒ Object
- #sinatra_init_data(method, sinatra, &block) ⇒ Object
- #sinatra_response(sinatra, method) ⇒ Object
- #sinatra_response_create_data(sinatra, response, method) ⇒ Object
- #sinatra_response_create_error(sinatra, response, method) ⇒ Object
- #sinatra_response_create_redirect(sinatra, response, method) ⇒ Object
- #sinatra_response_type(response) ⇒ Object
-
#sinatra_set_instance_variable(sinatra, name, value) ⇒ Object
————————–.
- #singleton(name, init_block = nil, &block) ⇒ Object
- #singleton? ⇒ Boolean
- #type ⇒ Object
Constructor Details
#initialize(sinatra, name, singleton, collection, parent, init_block) ⇒ Resource
Returns a new instance of Resource.
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/nested.rb', line 42 def initialize(sinatra, name, singleton, collection, parent, init_block) raise SingletonAndCollectionError.new if singleton && collection raise NameMissingError.new if (singleton || collection) && !name @sinatra = sinatra @name = name @singleton = singleton @collection = collection @parent = parent @resources = [] @actions = [] init &-> do fetched = instance_exec(&(init_block||FETCH)) # puts "set @#{@__resource.instance_variable_name} to #{fetched.inspect} for #{self}" # self.instance_variable_set("@#{@__resource.instance_variable_name}", fetched) @__resource.sinatra_set_instance_variable(self, @__resource.instance_variable_name, fetched) end if member? __serialize_args = @parent.instance_variable_get("@__serialize_args") __serialize_block = @parent.instance_variable_get("@__serialize_block") serialize *__serialize_args, &__serialize_block else serialize &->(obj) { raise "implement serializer for #{@__resource.type} #{@__resource.name}" } end end |
Instance Attribute Details
#actions ⇒ Object (readonly)
Returns the value of attribute actions.
40 41 42 |
# File 'lib/nested.rb', line 40 def actions @actions end |
#name ⇒ Object (readonly)
Returns the value of attribute name.
40 41 42 |
# File 'lib/nested.rb', line 40 def name @name end |
#parent ⇒ Object (readonly)
Returns the value of attribute parent.
40 41 42 |
# File 'lib/nested.rb', line 40 def parent @parent end |
#resources ⇒ Object (readonly)
Returns the value of attribute resources.
40 41 42 |
# File 'lib/nested.rb', line 40 def resources @resources end |
Instance Method Details
#child_resource(name, singleton, collection, init_block, &block) ⇒ Object
170 171 172 173 174 |
# File 'lib/nested.rb', line 170 def child_resource(name, singleton, collection, init_block, &block) Resource.new(@sinatra, name, singleton, collection, self, init_block) .tap{|r| r.instance_eval(&block)} .tap{|r| @resources << r} end |
#collection? ⇒ Boolean
80 81 82 |
# File 'lib/nested.rb', line 80 def collection? @collection == true end |
#create_sinatra_route(method, action, &block) ⇒ Object
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 |
# File 'lib/nested.rb', line 291 def create_sinatra_route(method, action, &block) @actions << {method: method, action: action, block: block} resource = self route = resource.route({}, action) puts "sinatra router [#{method}] #{@sinatra.nested_config[:prefix]}#{route}" @sinatra.send(method, route) do def self.error() errors.add(:base, ) end def self.errors @__errors ||= ActiveModel::Errors.new({}) end content_type :json resource.self_and_parents.reverse.each do |res| res.sinatra_init(self) end resource.send(:"sinatra_exec_#{method}_block", self, &block) resource.sinatra_response(self, method) end end |
#delete(action = nil, &block) ⇒ Object
152 153 154 |
# File 'lib/nested.rb', line 152 def delete(action=nil, &block) create_sinatra_route :delete, action, &block end |
#get(action = nil, &block) ⇒ Object
140 141 142 |
# File 'lib/nested.rb', line 140 def get(action=nil, &block) create_sinatra_route :get, action, &(block||proc {}) end |
#init(&block) ⇒ Object
110 111 112 |
# File 'lib/nested.rb', line 110 def init(&block) @__init = block end |
#instance_variable_name ⇒ Object
176 177 178 179 180 181 182 183 184 |
# File 'lib/nested.rb', line 176 def instance_variable_name if @name @name.to_s.send(collection? ? :pluralize : :singularize).to_sym elsif member? && @parent @parent.name.to_s.singularize.to_sym else nil end end |
#many(name, init_block = nil, &block) ⇒ Object
160 161 162 163 |
# File 'lib/nested.rb', line 160 def many(name, init_block=nil, &block) raise ManyInManyError.new "do not nest many in many" if collection? child_resource(name, false, true, init_block, &block) end |
#member? ⇒ Boolean
76 77 78 |
# File 'lib/nested.rb', line 76 def member? !singleton? && !collection? end |
#one(name = nil, init_block = nil, &block) ⇒ Object
165 166 167 168 |
# File 'lib/nested.rb', line 165 def one(name=nil, init_block=nil, &block) raise OneWithNameInManyError.new("call one (#{name}) without name argument when nested in a many (#{@name})") if name && collection? child_resource(name, false, false, init_block, &block) end |
#parents ⇒ Object
186 187 188 |
# File 'lib/nested.rb', line 186 def parents (@parent ? @parent.parents + [@parent] : []) end |
#post(action = nil, &block) ⇒ Object
144 145 146 |
# File 'lib/nested.rb', line 144 def post(action=nil, &block) create_sinatra_route :post, action, &block end |
#put(action = nil, &block) ⇒ Object
148 149 150 |
# File 'lib/nested.rb', line 148 def put(action=nil, &block) create_sinatra_route :put, action, &block end |
#route(args = {}, action = nil) ⇒ Object
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/nested.rb', line 114 def route(args={}, action=nil) "".tap do |r| r << @parent.route(args) if @parent if singleton? r << "/" + @name.to_s.singularize elsif collection? r << "/" + @name.to_s.pluralize else if @name r << "/" + @name.to_s.pluralize end r << "/" key = ((@name || @parent.name).to_s.singularize + "_id").to_sym if args.key?(key) r << args[key].to_s else r << ":#{key}" end end r << "/#{action}" if action end end |
#self_and_parents ⇒ Object
190 191 192 |
# File 'lib/nested.rb', line 190 def self_and_parents (self.parents + [self]).reverse end |
#serialize(*args, &block) ⇒ Object
96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/nested.rb', line 96 def serialize(*args, &block) raise "pass either *args or &block" if args.empty? && !block && !member? @__serialize_args = args @__serialize_block = block @__serialize = ->(obj) do obj = self.instance_exec(obj, &block) if block obj = obj.attributes if obj.is_a?(ActiveRecord::Base) obj = obj.symbolize_keys.slice(*args) unless args.empty? obj end end |
#sinatra_exec_delete_block(sinatra, &block) ⇒ Object
211 212 213 214 |
# File 'lib/nested.rb', line 211 def sinatra_exec_delete_block(sinatra, &block) sinatra_init_data(:delete, sinatra, &block) sinatra.instance_exec(*sinatra.instance_variable_get("@__data"), &block) end |
#sinatra_exec_get_block(sinatra, &block) ⇒ Object
206 207 208 209 |
# File 'lib/nested.rb', line 206 def sinatra_exec_get_block(sinatra, &block) sinatra_init_data(:get, sinatra, &block) sinatra.instance_exec(*sinatra.instance_variable_get("@__data"), &block) end |
#sinatra_exec_post_block(sinatra, &block) ⇒ Object
235 236 237 238 239 240 241 |
# File 'lib/nested.rb', line 235 def sinatra_exec_post_block(sinatra, &block) sinatra_init_data(:post, sinatra, &block) res = sinatra.instance_exec(*sinatra.instance_variable_get("@__data"), &block) sinatra.instance_variable_set("@#{self.instance_variable_name}", res) # TODO: do we need to check for existing variables here? # sinatra_set_instance_variable(sinatra, self.instance_variable_name, res) end |
#sinatra_exec_put_block(sinatra, &block) ⇒ Object
230 231 232 233 |
# File 'lib/nested.rb', line 230 def sinatra_exec_put_block(sinatra, &block) sinatra_init_data(:put, sinatra, &block) sinatra.instance_exec(*sinatra.instance_variable_get("@__data"), &block) end |
#sinatra_init(sinatra) ⇒ Object
201 202 203 204 |
# File 'lib/nested.rb', line 201 def sinatra_init(sinatra) sinatra.instance_variable_set("@__resource", self) sinatra.instance_exec(&@__init) end |
#sinatra_init_data(method, sinatra, &block) ⇒ Object
216 217 218 219 220 221 222 223 224 225 226 227 228 |
# File 'lib/nested.rb', line 216 def sinatra_init_data(method, sinatra, &block) raw_data = if [:put, :post].include?(method) sinatra.request.body.rewind HashWithIndifferentAccess.new(JSON.parse(sinatra.request.body.read)) elsif [:get, :delete].include?(method) sinatra.params else {} end sinatra.instance_variable_set("@__raw_data", raw_data) sinatra.instance_variable_set("@__data", raw_data.values_at(*block.parameters.map(&:last))) end |
#sinatra_response(sinatra, method) ⇒ Object
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
# File 'lib/nested.rb', line 247 def sinatra_response(sinatra, method) response = if sinatra.errors.empty? sinatra.instance_variable_get("@#{self.instance_variable_name}") else sinatra.errors end response = self.send(:"sinatra_response_create_#{sinatra_response_type(response)}", sinatra, response, method) case response when Nested::Redirect then sinatra.redirect(response.url) when String then response else response.to_json end end |
#sinatra_response_create_data(sinatra, response, method) ⇒ Object
270 271 272 273 274 275 276 277 278 |
# File 'lib/nested.rb', line 270 def sinatra_response_create_data(sinatra, response, method) data = if response && collection? && method != :post response.to_a.map{|e| sinatra.instance_exec(e, &@__serialize) } else sinatra.instance_exec(response, &@__serialize) end {data: data, ok: true} end |
#sinatra_response_create_error(sinatra, response, method) ⇒ Object
280 281 282 283 284 285 286 287 288 289 |
# File 'lib/nested.rb', line 280 def sinatra_response_create_error(sinatra, response, method) errors = response.is_a?(ActiveModel::Errors) ? response : response.errors data = errors.to_hash.inject({}) do |memo, e| memo[e[0]] = e[1][0] memo end {data: data, ok: false} end |
#sinatra_response_create_redirect(sinatra, response, method) ⇒ Object
266 267 268 |
# File 'lib/nested.rb', line 266 def sinatra_response_create_redirect(sinatra, response, method) response end |
#sinatra_response_type(response) ⇒ Object
243 244 245 |
# File 'lib/nested.rb', line 243 def sinatra_response_type(response) (response.is_a?(ActiveModel::Errors) || (response.respond_to?(:errors) && !response.errors.empty?)) ? :error : (response.is_a?(Nested::Redirect) ? :redirect : :data) end |
#sinatra_set_instance_variable(sinatra, name, value) ⇒ Object
196 197 198 199 |
# File 'lib/nested.rb', line 196 def sinatra_set_instance_variable(sinatra, name, value) raise "variable @#{name} already defined" if sinatra.instance_variable_defined?(:"@#{name}") sinatra.instance_variable_set(:"@#{name}", value) end |
#singleton(name, init_block = nil, &block) ⇒ Object
156 157 158 |
# File 'lib/nested.rb', line 156 def singleton(name, init_block=nil, &block) child_resource(name, true, false, init_block, &block) end |
#singleton? ⇒ Boolean
72 73 74 |
# File 'lib/nested.rb', line 72 def singleton? @singleton == true end |
#type ⇒ Object
84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/nested.rb', line 84 def type if singleton? :singleton elsif member? :member elsif collection? :collection else raise "undefined" end end |