ananke 1.1.3 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,181 @@
1
+ require 'json'
2
+ require 'sinatra/base'
3
+
4
+ module Sinatra
5
+ module Ananke
6
+
7
+ class Serialize
8
+ class << self
9
+ def can_serialize?(obj) obj.class != Array and obj.instance_variables.empty? end
10
+
11
+ def to_h(obj, options = {})
12
+ ret = {}
13
+ if obj.class == Hash
14
+ obj.each do |k, v|
15
+ ret[k.to_sym] = (can_serialize?(v) ? v : Serialize.to_h(v, options))
16
+ end
17
+ elsif obj.class == Array
18
+ ret = obj.collect {|i| Serialize.to_h(i, options)}
19
+ elsif obj.instance_variables.empty?
20
+ ret = obj
21
+ else
22
+ obj.instance_variables.each do |e|
23
+ value = obj.instance_variable_get e.to_sym
24
+ ret[e[1..-1]] = (can_serialize?(value) ? value : Serialize.to_h(value, options))
25
+ end
26
+ end
27
+ if ret.respond_to? :delete_if
28
+ ret.delete_if {|k,v| v.nil? || v == ''} if ret.class == Hash && options[:remove_empty]
29
+ ret.delete_if {|i| i.nil? || i == ''} if ret.class == Array && options[:remove_empty]
30
+ ret = {} if ret.empty?
31
+ end
32
+ ret
33
+ end
34
+
35
+ def to_a(obj, options = {}) ret = Serialize.to_h(obj, options); ret.class == Array && ret || [ret] end
36
+ def to_j(obj, options = {}) Serialize.to_h(obj, options).to_json end
37
+ def to_j_pretty(obj, options = {}) JSON.pretty_generate(Serialize.to_h(obj, options), opts = {:indent => ' '}) end
38
+ end
39
+ end
40
+
41
+ module Helpers
42
+ def collect_input_params(params, &block)
43
+ block_params = block.parameters.collect {|p| p[1]}
44
+ block_params.collect do |param|
45
+ error(400, "Missing parameter - #{param}") unless params.has_key? param.to_s
46
+ value = params[param]
47
+ case
48
+ when value.to_i.to_s == value; value.to_i
49
+ when value.to_f.to_s == value; value.to_f
50
+ else value
51
+ end
52
+ end
53
+ end
54
+
55
+ def inject_app(resource_classes)
56
+ resource_classes.each do |klass|
57
+ klass.send :define_method, :app, do klass.class_variable_get :@@app end unless klass.method_defined? :app
58
+ klass.send :class_variable_set, :@@app, self
59
+ end
60
+ end
61
+ end
62
+
63
+ public
64
+
65
+ class << self
66
+ attr_accessor :resource_module
67
+ end
68
+
69
+ def self.registered(app)
70
+ app.helpers Ananke::Helpers
71
+ end
72
+
73
+ attr_reader :resource_name, :resource_id, :resource_items, :resource_link_to, :resource_classes, :resource_mime, :resource_remove_empty
74
+ def resource_link_self?() @resource_link_self end
75
+
76
+ def make_resource(name, options = {})
77
+ reset!
78
+ options[:id] ||= :id
79
+ options[:items] ||= :items
80
+ options[:link_self] = options.has_key?(:link_self) ? options[:link_self] : true
81
+ options[:link_to] ||= []
82
+ options[:classes] ||= []
83
+
84
+ @resource_name = name
85
+ @resource_id = options[:id]
86
+ @resource_items = options[:items]
87
+ @resource_link_self = options[:link_self]
88
+ @resource_link_to = options[:link_to]
89
+ @resource_classes ||= []
90
+ @resource_mime = options[:mime]
91
+ @resource_remove_empty = options.has_key?(:remove_empty) ? options[:remove_empty] : false
92
+
93
+ options[:classes].each {|c| add_class c}
94
+ end
95
+
96
+ def add_class(klass)
97
+ @resource_classes << klass
98
+ klass.public_instance_methods(false).each do |method_name|
99
+ block = klass.new.method(method_name).to_proc
100
+ if [:one,:all,:add,:edit,:trash].include? method_name
101
+ method(method_name).call({}, &block)
102
+ else
103
+ get!(method_name, {}, &block) if block.arity <= 1
104
+ post!(method_name, {}, &block) if block.arity > 1
105
+ end
106
+ end
107
+ end
108
+
109
+ def get!(path, options={}, &block) rest :get, path, options, &block end
110
+ def post!(path, options={}, &block) rest :post, path, options, &block end
111
+ def put!(path, options={}, &block) rest :put, path, options, &block end
112
+ def delete!(path, options={}, &block) rest :delete, path, options, &block end
113
+
114
+ def one(options={}, &block) rest :get, ":#{resource_id}", options, &block end
115
+ def all(options={}, &block) rest :get, '?', options, &block end
116
+ def add(options={}, &block) rest :post, '?', options, &block end
117
+ def edit(options={}, &block) rest :put, ":#{resource_id}", options, &block end
118
+ def trash(options={}, &block) rest :delete, ":#{resource_id}", options, &block end
119
+
120
+ private
121
+
122
+ def rest(type, path, options={}, &block)
123
+ res = {
124
+ :name => resource_name,
125
+ :id => resource_id,
126
+ :items => resource_items,
127
+ :link_self => resource_link_self?,
128
+ :link_to => resource_link_to,
129
+ :classes => resource_classes,
130
+ :remove_empty => resource_remove_empty
131
+ }
132
+ block_params = block.parameters.collect {|p| p[1]}
133
+ path = "#{path}/:#{block_params[0]}" if [:get,:put,:delete].include?(type) && block_params.length >= 1 && path != ":#{block_params[0]}"
134
+ method(type).call "/#{resource_name}/#{path}", options, do
135
+ inject_app(res[:classes])
136
+ input_params = collect_input_params(params, &block)
137
+
138
+ result = instance_exec(*input_params, &block)
139
+ result = Serialize.to_a(result, :remove_empty => res[:remove_empty])
140
+ result = result.empty? && {} || {res[:items] => Serialize.to_h(result, :remove_empty => res[:remove_empty])}
141
+
142
+ #inject links
143
+ result[res[:items]].each do |item|
144
+ next unless item.respond_to?(:has_key?) && item.has_key?(res[:id])
145
+ links = []
146
+ links << {:rel => :self, :href => "/#{res[:name]}/#{item[res[:id]]}"} if res[:link_self]
147
+ links.concat(res[:link_to].collect { |link| {:rel => link, :href => "/#{link}/#{res[:name]}/#{item[res[:id]]}"}})
148
+ item[:links] = links unless links.empty?
149
+ end
150
+
151
+ content_type :json
152
+ Serialize.to_j result
153
+ end
154
+ end
155
+
156
+ end
157
+
158
+ register Ananke
159
+ helpers Ananke::Helpers
160
+ end
161
+
162
+ module DSL
163
+ def resource(name, options={}, &block)
164
+ resource_module = Sinatra::Ananke.resource_module && Sinatra::Ananke.resource_module.to_s.capitalize.to_sym || nil
165
+ Object.const_set(resource_module, Module::new) if resource_module && !Object.const_get(resource_module)
166
+ Object.const_set(options[:module].to_s.capitalize, Module::new) if options[:module] && [String, Symbol].include?(options[:module].class)
167
+ container = options[:module] ? Object.const_get(options[:module].to_s.capitalize) : self.respond_to?(:name) ? self : resource_module ? Object.const_get(resource_module) : Object
168
+ full_name = name.capitalize.to_sym
169
+ container::const_set(full_name, Class::new(Sinatra::Base) do
170
+ register Sinatra::Ananke
171
+ end) unless container::const_defined?(full_name)
172
+
173
+ klass = container::const_get(full_name)
174
+ klass.make_resource name, options
175
+ klass.instance_eval(&block) if block_given?
176
+ end
177
+ end
178
+
179
+ include DSL
180
+ #Defaults
181
+ Sinatra::Ananke.resource_module=nil
@@ -0,0 +1,3 @@
1
+ module Ananke
2
+ VERSION = "2.0.0"
3
+ end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: ananke
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 1.1.3
5
+ version: 2.0.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Andries Coetzee
@@ -10,40 +10,39 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-03-28 00:00:00 +02:00
14
- default_executable:
13
+ date: 2011-09-13 00:00:00 Z
15
14
  dependencies:
16
15
  - !ruby/object:Gem::Dependency
17
- name: sinatra
16
+ name: colored
18
17
  prerelease: false
19
18
  requirement: &id001 !ruby/object:Gem::Requirement
20
19
  none: false
21
20
  requirements:
22
21
  - - ~>
23
22
  - !ruby/object:Gem::Version
24
- version: 1.1.2
23
+ version: "1.2"
25
24
  type: :runtime
26
25
  version_requirements: *id001
27
26
  - !ruby/object:Gem::Dependency
28
- name: colored
27
+ name: json
29
28
  prerelease: false
30
29
  requirement: &id002 !ruby/object:Gem::Requirement
31
30
  none: false
32
31
  requirements:
33
32
  - - ~>
34
33
  - !ruby/object:Gem::Version
35
- version: "1.2"
34
+ version: 1.6.0
36
35
  type: :runtime
37
36
  version_requirements: *id002
38
37
  - !ruby/object:Gem::Dependency
39
- name: json
38
+ name: sinatra
40
39
  prerelease: false
41
40
  requirement: &id003 !ruby/object:Gem::Requirement
42
41
  none: false
43
42
  requirements:
44
43
  - - ~>
45
44
  - !ruby/object:Gem::Version
46
- version: 1.5.1
45
+ version: 1.2.6
47
46
  type: :runtime
48
47
  version_requirements: *id003
49
48
  - !ruby/object:Gem::Dependency
@@ -54,7 +53,7 @@ dependencies:
54
53
  requirements:
55
54
  - - ~>
56
55
  - !ruby/object:Gem::Version
57
- version: 0.5.6
56
+ version: 0.6.1
58
57
  type: :development
59
58
  version_requirements: *id004
60
59
  - !ruby/object:Gem::Dependency
@@ -65,7 +64,7 @@ dependencies:
65
64
  requirements:
66
65
  - - ~>
67
66
  - !ruby/object:Gem::Version
68
- version: 0.8.7
67
+ version: 0.9.2
69
68
  type: :development
70
69
  version_requirements: *id005
71
70
  - !ruby/object:Gem::Dependency
@@ -76,7 +75,7 @@ dependencies:
76
75
  requirements:
77
76
  - - ~>
78
77
  - !ruby/object:Gem::Version
79
- version: 2.5.0
78
+ version: 2.6.0
80
79
  type: :development
81
80
  version_requirements: *id006
82
81
  - !ruby/object:Gem::Dependency
@@ -87,59 +86,28 @@ dependencies:
87
86
  requirements:
88
87
  - - ~>
89
88
  - !ruby/object:Gem::Version
90
- version: 0.3.9
89
+ version: 0.5.2
91
90
  type: :development
92
91
  version_requirements: *id007
93
- description: Full REST Implementation on top of Sinatra
94
- email: andriesc@mixtel.com
92
+ description: Ananke enables a new kind of ReST implementation
93
+ email:
94
+ - andriesc@lime-square.net
95
95
  executables: []
96
96
 
97
97
  extensions: []
98
98
 
99
- extra_rdoc_files:
100
- - README.rdoc
99
+ extra_rdoc_files: []
100
+
101
101
  files:
102
- - lib/ananke.rb
103
- - lib/version.rb
104
- - lib/ananke/settings.rb
105
- - lib/ananke/linking.rb
106
- - lib/ananke/routing.rb
107
- - lib/ananke/validation.rb
108
- - lib/ananke/helpers.rb
109
- - lib/ananke/serialize.rb
110
- - spec/dumping.rb
111
- - spec/cov_adapter.rb
112
- - spec/lib/ananke_spec.rb
113
- - spec/lib/validation_spec.rb
114
- - spec/lib/out_spec.rb
115
- - spec/lib/json_spec.rb
116
- - spec/lib/serialize_spec.rb
117
- - spec/lib/link_to_spec.rb
118
- - spec/lib/route_for_spec.rb
119
- - spec/lib/error_spec.rb
120
- - spec/lib/linked_spec.rb
121
- - spec/spec_helper.rb
122
- - spec/call_chain.rb
123
- - spec/nice_formatter.rb
124
- - Gemfile
125
- - Rakefile
102
+ - lib/sinatra/ananke.rb
103
+ - lib/sinatra/version.rb
126
104
  - README.rdoc
127
- has_rdoc: true
128
- homepage: https://github.com/HasAndries/ananke
105
+ homepage: http://github.com/hasandries/ananke
129
106
  licenses: []
130
107
 
131
- post_install_message: |
132
- **************************************************
133
-
134
- Thank you for installing ananke-1.1.3
135
-
136
- Please be sure to look at README.rdoc to see what might have changed
137
- since the last release and how to use this GEM.
138
-
139
- **************************************************
108
+ post_install_message:
109
+ rdoc_options: []
140
110
 
141
- rdoc_options:
142
- - --charset=UTF-8
143
111
  require_paths:
144
112
  - lib
145
113
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -151,28 +119,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
151
119
  required_rubygems_version: !ruby/object:Gem::Requirement
152
120
  none: false
153
121
  requirements:
154
- - - ">="
122
+ - - ~>
155
123
  - !ruby/object:Gem::Version
156
- version: "0"
124
+ version: 1.8.10
157
125
  requirements: []
158
126
 
159
127
  rubyforge_project:
160
- rubygems_version: 1.5.0
128
+ rubygems_version: 1.8.10
161
129
  signing_key:
162
130
  specification_version: 3
163
- summary: ananke-1.1.3
164
- test_files:
165
- - spec/dumping.rb
166
- - spec/cov_adapter.rb
167
- - spec/lib/ananke_spec.rb
168
- - spec/lib/validation_spec.rb
169
- - spec/lib/out_spec.rb
170
- - spec/lib/json_spec.rb
171
- - spec/lib/serialize_spec.rb
172
- - spec/lib/link_to_spec.rb
173
- - spec/lib/route_for_spec.rb
174
- - spec/lib/error_spec.rb
175
- - spec/lib/linked_spec.rb
176
- - spec/spec_helper.rb
177
- - spec/call_chain.rb
178
- - spec/nice_formatter.rb
131
+ summary: The Awesome ReST framework
132
+ test_files: []
133
+
data/Gemfile DELETED
@@ -1,15 +0,0 @@
1
- source "http://rubygems.org"
2
-
3
- gem "colored", "~>1.2"
4
- gem "json", "~>1.5.1"
5
- gem "sinatra", "~>1.1.2"
6
-
7
- #group :development, :test do
8
- gem "rack-test", "~>0.5.6"
9
- gem "rake", "~>0.8.7"
10
- gem "rspec", "~>2.5.0"
11
- gem 'simplecov', '~>0.4.0'
12
- #end
13
-
14
-
15
-
data/Rakefile DELETED
@@ -1,65 +0,0 @@
1
- require 'rubygems'
2
- require "rake"
3
- require "rake/rdoctask"
4
- require 'rake/gempackagetask'
5
- require "rspec/core/rake_task"
6
-
7
- require File.expand_path("../lib/version", __FILE__)
8
- gemspec = Gem::Specification.new do |gem|
9
- gem.name = "ananke"
10
- gem.version = Ananke::VERSION
11
- gem.platform = Gem::Platform::RUBY
12
- gem.authors = ["Andries Coetzee"]
13
- gem.email = "andriesc@mixtel.com"
14
- gem.summary = "#{gem.name}-#{Ananke::VERSION}"
15
- gem.description = "Full REST Implementation on top of Sinatra"
16
- gem.homepage = "https://github.com/HasAndries/ananke"
17
-
18
- gem.rubygems_version = "1.5.0"
19
-
20
- gem.files = FileList['lib/**/*', 'spec/**/*', 'Gemfile', 'Rakefile', 'README.rdoc']
21
- gem.test_files = FileList['spec/**/*']
22
- gem.extra_rdoc_files = [ "README.rdoc" ]
23
- gem.rdoc_options = ["--charset=UTF-8"]
24
- gem.require_path = "lib"
25
-
26
- gem.post_install_message = %Q{**************************************************
27
-
28
- Thank you for installing #{gem.summary}
29
-
30
- Please be sure to look at README.rdoc to see what might have changed
31
- since the last release and how to use this GEM.
32
-
33
- **************************************************
34
- }
35
- gem.add_dependency "sinatra", "~> 1.1.2"
36
- gem.add_dependency "colored", "~> 1.2"
37
- gem.add_dependency "json", "~> 1.5.1"
38
-
39
- gem.add_development_dependency "rack-test", "~> 0.5.6"
40
- gem.add_development_dependency "rake", "~> 0.8.7"
41
- gem.add_development_dependency "rspec", "~> 2.5.0"
42
- gem.add_development_dependency "simplecov", "~> 0.3.9"
43
- end
44
-
45
- Rake::GemPackageTask.new(gemspec) do |pkg|
46
- pkg.need_tar = true
47
- end
48
-
49
- desc %{Build the gemspec file.}
50
- task :gemspec do
51
- gemspec.validate
52
- File.open("#{gemspec.name}.gemspec", 'w'){|f| f.write gemspec.to_ruby }
53
- end
54
-
55
- RSpec::Core::RakeTask.new(:test) do |t|
56
- t.rspec_opts = ["-c", "-f progress", "-r ./spec/spec_helper.rb"]
57
- t.pattern = 'spec/**/*_spec.rb'
58
- end
59
-
60
- RSpec::Core::RakeTask.new(:doc) do |t|
61
- t.rspec_opts = ["-c" "-r ./spec/nice_formatter.rb", "-f NiceFormatter", "-o doc.htm"]
62
- t.pattern = 'spec/**/*_spec.rb'
63
- end
64
-
65
- task :default => [:test]
@@ -1,85 +0,0 @@
1
- require 'json'
2
- module Ananke
3
-
4
- extend Colored
5
-
6
- public
7
-
8
- def get_repository_module(path)
9
- repository = nil
10
- repository = Module.const_get(Ananke.repository) if Module.const_defined?(Ananke.repository)
11
- repository = repository.const_get("#{path.capitalize}".to_sym) if !repository.nil? && repository.const_defined?("#{path.capitalize}".to_sym)
12
- repository
13
- end
14
-
15
- def get_id(obj, key)
16
- if !key
17
- out :warning, "Cannot get id on object #{obj}, key is nil"
18
- return nil
19
- end
20
- obj.class == Hash && obj.has_key?(key) ? obj[key] : obj.respond_to?(key) ? obj.instance_variable_get("@#{key}") : nil
21
- end
22
-
23
- def out(type, message)
24
- return if !Ananke.settings[:output]
25
- message = case
26
- when type == :info && Ananke.settings[:info]
27
- message.blue
28
- when type == :warning && Ananke.settings[:warning]
29
- message.yellow
30
- when type == :error && Ananke.settings[:error]
31
- message.red
32
- end
33
- puts message unless message.nil?
34
- message
35
- end
36
-
37
- def symbolize_keys(hash)
38
- new_hash = {}
39
- hash.each{|k,v| new_hash[k.to_sym] = Hash === v ? symbolize_keys(v) : v}
40
- new_hash
41
- end
42
-
43
- def collect_params(params)
44
- new_params = {}
45
- params.each do |k,v|
46
- json = symbolize_keys(JSON.parse(k)) if v.nil?
47
- if !json.nil? && !json.empty?
48
- new_params.merge!(json)
49
- else
50
- new_params[k.to_sym] = v
51
- end
52
- end
53
- new_params
54
- end
55
-
56
- def define_repository_call(mod, method_name)
57
- inputs = mod.method(method_name).parameters
58
- repository_name = mod.name.split('::').last.downcase
59
- call_def = "def self.call_#{repository_name}_#{method_name}(params)\n"
60
- case inputs.length
61
- when 0
62
- call_def << " #{mod}.send(:#{method_name})\n"
63
- when 1
64
- call_def << " param = params[:key] ? params[:key] : params.values.first\n"
65
- call_def << " #{mod}.send(:#{method_name}, param)\n"
66
- else
67
- input_array = []
68
- inputs.each{|i| input_array << "params[:#{i[1]}]"}
69
- call_def << " #{mod}.send(:#{method_name}, #{input_array.join(',')})\n"
70
- end
71
- call_def << "end"
72
- Ananke.send(:eval, call_def)
73
- end
74
-
75
- def repository_call(mod, method_name, params = {})
76
- repository_name = mod.name.split('::').last.downcase
77
- begin
78
- return Ananke.send("call_#{repository_name}_#{method_name}", params), 200
79
- rescue StandardError => error
80
- raise if !error.message.start_with?(method_name.to_s)
81
- message = error.message.split(method_name.to_s).last.split('-').last.split(':').last.strip
82
- return message, 400
83
- end
84
- end
85
- end
@@ -1,35 +0,0 @@
1
- module Ananke
2
- def build_links(link_list, link_to_list, path, id, repository)
3
- return if !Ananke.settings[:links]
4
-
5
- links = id ? build_link_self(path, id) : []
6
- links += build_link_list(path, id, repository, link_list)
7
- links += build_link_to_list(path, id, link_to_list)
8
-
9
- links
10
- end
11
- #===========================SELF===============================
12
- def build_link_self(path, id)
13
- uri = "/#{path.to_s}"
14
- uri << "/#{id}" if id
15
- [{:rel => 'self', :uri => uri}]
16
- end
17
- #===========================LINKED=============================
18
- def build_link_list(path, id, repository, link_list)
19
- links = []
20
- link_list.each do |link|
21
- repository_method = "#{link[:rel]}_id_list"
22
- if repository.respond_to?(repository_method)
23
- id_list = repository.send(repository_method, id)
24
- links = id_list.collect{|i| {:rel => "#{link[:rel]}", :uri => "/#{link[:rel]}/#{i}"}}
25
- else
26
- out :error, "#{path} - #{repository} does not respond to '#{repository_method.to_s}'"
27
- end
28
- end
29
- links
30
- end
31
- #===========================LINK_TO============================
32
- def build_link_to_list(path, id, link_to_list)
33
- link_to_list.collect { |link| {:rel => "#{link[:rel]}", :uri => "/#{link[:rel]}/#{path.to_s.split('/')[0]}/#{id}"} }
34
- end
35
- end