Class: Nested::Resource

Inherits:
Object
  • Object
show all
Defined in:
lib/nested.rb

Constant Summary collapse

FETCH =
->(resource, ctrl) 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 = ctrl.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: ctrl.params["#{resource.name.to_s.singularize}_id"]).first
  else
    parent_obj.where(id: ctrl.params["#{parent_resource.name.to_s.singularize}_id"]).first
  end
end

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(sinatra, name, singleton, collection, parent) ⇒ Resource

Returns a new instance of Resource.



30
31
32
33
34
35
36
37
38
39
40
# File 'lib/nested.rb', line 30

def initialize(sinatra, name, singleton, collection, parent)
  raise SingletonAndCollectionError.new if singleton && collection

  @sinatra = sinatra
  @name = name
  @singleton = singleton
  @collection = collection
  @parent = parent
  @resources = []
  @actions = []
end

Instance Attribute Details

#actionsObject (readonly)

Returns the value of attribute actions.



28
29
30
# File 'lib/nested.rb', line 28

def actions
  @actions
end

#nameObject (readonly)

Returns the value of attribute name.



28
29
30
# File 'lib/nested.rb', line 28

def name
  @name
end

#parentObject (readonly)

Returns the value of attribute parent.



28
29
30
# File 'lib/nested.rb', line 28

def parent
  @parent
end

#resourcesObject (readonly)

Returns the value of attribute resources.



28
29
30
# File 'lib/nested.rb', line 28

def resources
  @resources
end

Instance Method Details

#child_resource(name, singleton, collection, &block) ⇒ Object



120
121
122
123
124
# File 'lib/nested.rb', line 120

def child_resource(name, singleton, collection, &block)
   Resource.new(@sinatra, name, singleton, collection, self)
    .tap{|r| r.instance_eval(&block)}
    .tap{|r| @resources << r}
end

#collection?Boolean



50
51
52
# File 'lib/nested.rb', line 50

def collection?
  @collection == true
end

#create_sinatra_route(method, action, &block) ⇒ Object



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/nested.rb', line 138

def create_sinatra_route(method, action, &block)
  @actions << {method: method, actions: action}

  resource = self

  puts "sinatra router [#{method}] #{@sinatra.prefix}#{resource.route}"

  @sinatra.send(method, resource.route) do
    content_type :json

    resource.self_and_parents.reverse.each do |res|
      resource_obj = res.fetch_object(self)

      puts "set @#{res.instance_variable_name} to #{resource_obj.inspect} for #{self}"
      instance_variable_set("@#{res.instance_variable_name}", resource_obj)
    end

    case response = instance_exec(resource, &block)
      when String then  response
      else              response.to_json
    end
  end
end

#delete(action = nil, &block) ⇒ Object



102
103
104
# File 'lib/nested.rb', line 102

def delete(action=nil, &block)
  create_sinatra_route :delete, action, &block
end

#fetch(&block) ⇒ Object



54
55
56
# File 'lib/nested.rb', line 54

def fetch(&block)
  @__fetch = block
end

#fetch_object(ctrl) ⇒ Object



58
59
60
# File 'lib/nested.rb', line 58

def fetch_object(ctrl)
  (@__fetch || FETCH).call(self, ctrl)
end

#get(action = nil, &block) ⇒ Object



86
87
88
# File 'lib/nested.rb', line 86

def get(action=nil, &block)
  create_sinatra_route :get, action, &(block || get_default)
end

#get_defaultObject



90
91
92
# File 'lib/nested.rb', line 90

def get_default
  ->(resource) { instance_variable_get("@#{resource.instance_variable_name}") }
end

#instance_variable_nameObject



126
127
128
# File 'lib/nested.rb', line 126

def instance_variable_name
  @name.to_s.send(collection? ? :pluralize : :singularize).to_sym
end

#many(name, &block) ⇒ Object



110
111
112
113
# File 'lib/nested.rb', line 110

def many(name, &block)
  raise ManyInManyError.new "do not nest many in many" if collection?
  child_resource(name, false, true, &block)
end

#member?Boolean



46
47
48
# File 'lib/nested.rb', line 46

def member?
  !singleton? && !collection?
end

#one(name = nil, &block) ⇒ Object



115
116
117
118
# File 'lib/nested.rb', line 115

def one(name=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, &block)
end

#parentsObject



130
131
132
# File 'lib/nested.rb', line 130

def parents
  (@parent ? @parent.parents + [@parent] : [])
end

#post(action = nil, &block) ⇒ Object



94
95
96
# File 'lib/nested.rb', line 94

def post(action=nil, &block)
  create_sinatra_route :post, action, &block
end

#put(action = nil, &block) ⇒ Object



98
99
100
# File 'lib/nested.rb', line 98

def put(action=nil, &block)
  create_sinatra_route :put, action, &block
end

#route(args = {}) ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/nested.rb', line 62

def route(args={})
  "".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
  end
end

#self_and_parentsObject



134
135
136
# File 'lib/nested.rb', line 134

def self_and_parents
  (self.parents + [self]).reverse
end

#singleton(name, &block) ⇒ Object



106
107
108
# File 'lib/nested.rb', line 106

def singleton(name, &block)
  child_resource(name, true, false, &block)
end

#singleton?Boolean



42
43
44
# File 'lib/nested.rb', line 42

def singleton?
  @singleton == true
end