ananke 1.1.3 → 2.0.0

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