well_rested 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,27 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ gem 'json'
7
+ gem 'activemodel'
8
+ gem 'activeresource'
9
+ gem 'uuidtools'
10
+
11
+ gem 'rest-client'
12
+ gem 'rest-client-components'
13
+
14
+ # Add dependencies to develop your gem here.
15
+ # Include everything needed to run rake, tests, features, etc.
16
+ group :development do
17
+ gem "rspec", "~> 2.8.0"
18
+ gem "rdoc", "~> 3.12"
19
+ gem "bundler", ">= 1.0.0"
20
+ gem "jeweler", "~> 1.8.3"
21
+ gem "rcov", ">= 0"
22
+
23
+ gem 'autotest'
24
+ gem 'fakeweb'
25
+ gem 'fakeweb-matcher'
26
+ #gem 'rack-cache'
27
+ end
@@ -0,0 +1,69 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ ZenTest (4.6.2)
5
+ activemodel (3.2.2)
6
+ activesupport (= 3.2.2)
7
+ builder (~> 3.0.0)
8
+ activeresource (3.2.2)
9
+ activemodel (= 3.2.2)
10
+ activesupport (= 3.2.2)
11
+ activesupport (3.2.2)
12
+ i18n (~> 0.6)
13
+ multi_json (~> 1.0)
14
+ autotest (4.4.6)
15
+ ZenTest (>= 4.4.1)
16
+ builder (3.0.0)
17
+ diff-lcs (1.1.3)
18
+ fakeweb (1.3.0)
19
+ fakeweb-matcher (1.2.2)
20
+ fakeweb (>= 1.2.5)
21
+ rspec (>= 1.2.0)
22
+ git (1.2.5)
23
+ i18n (0.6.0)
24
+ jeweler (1.8.3)
25
+ bundler (~> 1.0)
26
+ git (>= 1.2.5)
27
+ rake
28
+ rdoc
29
+ json (1.6.5)
30
+ mime-types (1.17.2)
31
+ multi_json (1.1.0)
32
+ rack (1.4.1)
33
+ rake (0.9.2.2)
34
+ rcov (1.0.0)
35
+ rdoc (3.12)
36
+ json (~> 1.4)
37
+ rest-client (1.6.7)
38
+ mime-types (>= 1.16)
39
+ rest-client-components (1.2.0)
40
+ rack (>= 1.0.1)
41
+ rest-client (>= 1.6.0, < 1.7.0)
42
+ rspec (2.8.0)
43
+ rspec-core (~> 2.8.0)
44
+ rspec-expectations (~> 2.8.0)
45
+ rspec-mocks (~> 2.8.0)
46
+ rspec-core (2.8.0)
47
+ rspec-expectations (2.8.0)
48
+ diff-lcs (~> 1.1.2)
49
+ rspec-mocks (2.8.0)
50
+ uuidtools (2.1.2)
51
+
52
+ PLATFORMS
53
+ ruby
54
+
55
+ DEPENDENCIES
56
+ activemodel
57
+ activeresource
58
+ autotest
59
+ bundler (>= 1.0.0)
60
+ fakeweb
61
+ fakeweb-matcher
62
+ jeweler (~> 1.8.3)
63
+ json
64
+ rcov
65
+ rdoc (~> 3.12)
66
+ rest-client
67
+ rest-client-components
68
+ rspec (~> 2.8.0)
69
+ uuidtools
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Deep Web Technologies, inc.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,140 @@
1
+ = well_rested
2
+
3
+ WellRested (WR) is a resource-based REST-API client library for Ruby.
4
+
5
+ Like ActiveResource, it supports ActiveRecord-style validations and works with Rails form helpers.
6
+
7
+ WellRested was created to address some limitations in ActiveResource:
8
+
9
+ - Supports transparent HTTP caching (via Rack::Cache / rest-client-components).
10
+ - Avoids race conditions when changing HTTP authentication by specifying it on an API object rather than in the Base class.
11
+ - Easy to override the object loading / serializing methods to modify attributes on the way in or out.
12
+ - Handles camel-cased attribute and resource names.
13
+ - Will not put file-extensions (e.g. .json) on the end of paths unless you tell it to.
14
+
15
+ == Features to Add
16
+
17
+ - XML support. Currently, only JSON is supported.
18
+
19
+ If you want to use WR, but are encountering a limitation, I encourage you to file an issue on GitHub
20
+ or to fork your own version and send a pull request with your changes.
21
+
22
+ == Installation
23
+
24
+ gem install well_rested
25
+
26
+ Or, if using bundler, add the following to your Gemfile
27
+
28
+ gem 'well_rested'
29
+
30
+ Then
31
+
32
+ bundle install
33
+
34
+ == Sample Usage with Rails
35
+
36
+ In app/models/base.rb
37
+
38
+ # It is often convenient to set your defaults in a base class.
39
+ class Base < WellRested::Base
40
+ self.protocol = 'https'
41
+ self.server = 'example.com:8888'
42
+
43
+ # Send and receive request bodies in JSON. This is the default.
44
+ self.body_formatter = WellRested::JSONFormatter.new
45
+ self.extension = '.json' # add '.json' to the end of URLs. Default is an empty string.
46
+
47
+ # Encode multi-word attributes names into lowerCamelCase. This is the default.
48
+ self.attribute_formatter = WellRested::CamelCaseFormatter.new(:lower)
49
+ end
50
+
51
+ In app/models/my_resource.rb
52
+
53
+ class MyResource < Base
54
+ self.path = '/users/:user_id/my_resources' # NOTE: Path must begin with a slash!
55
+
56
+ define_schema :id, :user_id, :name, :status => 'active' # status defaults to 'active'
57
+
58
+ # ActiveModel validations may be applied here.
59
+ # They will be checked before a save or create request is made.
60
+ validates :name, :length => { :maximum => 127 }, :presence => true
61
+ end
62
+
63
+ In app/controllers/application_controller.rb
64
+
65
+ before_filter :load_api
66
+
67
+ def load_api
68
+ @api = WellRested::API.new
69
+ # set basic auth
70
+ @api.user = 'username'
71
+ @api.password = 'pass'
72
+ end
73
+
74
+ In app/controllers/my_resources_controller.rb
75
+
76
+ def index
77
+ @my_resources = @api.find_many(MyResource, :user_id => current_user.id)
78
+ end
79
+
80
+ def create
81
+ @my_resource = MyResource.new(params[:my_resource])
82
+ @my_resource.user_id = current_user.id
83
+
84
+ # If current_user.id is 22, then this will POST to https://example.com:8888/users/22/my_resources
85
+ # with a JSON payload e.g. '{"name":"My Resource","user_id":22,"status":"active"}'
86
+ if @api.save(@my_resource)
87
+ flash[:notice] = 'Created resource!'
88
+ redirect_to my_resources_path
89
+ else
90
+ flash[:warning] = 'Error creating resource!'
91
+ render :new
92
+ end
93
+ end
94
+
95
+ def update
96
+ @my_resource = MyResource.new(params[:my_resource])
97
+
98
+ # Assuming @my_resource.user_id is 22 and @my_resource.id is 41
99
+ # If valid, PUT to https://example.com:8888/users/22/my_resources/41
100
+ # with a JSON payload e.g. '{"name":"My Resource","user_id":22,"status":"active","id":41}'
101
+ if @api.save(@my_resource)
102
+ flash[:notice] = 'Resource Saved!'
103
+ redirect_to @my_resource
104
+ else
105
+ flash[:error] 'Error saving resource!'
106
+ render :edit and return
107
+ end
108
+ end
109
+
110
+ def destroy
111
+ # If params[:id] is 41, then this will DELETE https://example.com:8888/users/22/my_resources/41
112
+ if @api.delete(MyResource, :user_id => current_user.id, :id => params[:id])
113
+ flash[:notice] = 'Deleted resource.'
114
+ else
115
+ # If the server returns a 422 and an errors attribute containing a list of error messages,
116
+ # they will automatically be added to the object's errors array.
117
+ flash[:error] = 'Failed to delete resource.'
118
+ end
119
+ redirect_to my_resources_path
120
+ end
121
+
122
+ # etc.
123
+
124
+ == Contributing to well_rested
125
+
126
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
127
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
128
+ * Fork the project.
129
+ * Start a feature/bugfix branch.
130
+ * Commit and push until you are happy with your contribution.
131
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
132
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
133
+
134
+ == Copyright
135
+
136
+ Copyright (c) 2012 Deep Web Technologies, inc. See LICENSE.txt for further details.
137
+
138
+ Written by Nick Urban.
139
+
140
+
@@ -0,0 +1,49 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "well_rested"
18
+ gem.homepage = "https://github.com/DeepWebTechnologies/well_rested"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{A Resource-based REST Client library (ActiveResource replacement).}
21
+ gem.description = %Q{An Active-Resource replacement that supports camel-cased APIs and HTTP caching, and avoids race conditions when changing authentication information on the fly.}
22
+ gem.email = "nickurban@gmail.com"
23
+ gem.authors = ["Nick Urban"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rspec/core'
29
+ require 'rspec/core/rake_task'
30
+ RSpec::Core::RakeTask.new(:spec) do |spec|
31
+ spec.pattern = FileList['spec/**/*_spec.rb']
32
+ end
33
+
34
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
35
+ spec.pattern = 'spec/**/*_spec.rb'
36
+ spec.rcov = true
37
+ end
38
+
39
+ task :default => :spec
40
+
41
+ require 'rdoc/task'
42
+ Rake::RDocTask.new do |rdoc|
43
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
44
+
45
+ rdoc.rdoc_dir = 'rdoc'
46
+ rdoc.title = "well_rested #{version}"
47
+ rdoc.rdoc_files.include('README*')
48
+ rdoc.rdoc_files.include('lib/**/*.rb')
49
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.6.0
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby -w
2
+
3
+ # RubyGems sets up the load path, but we're loading from the local directry too.
4
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
5
+
6
+ require 'rubygems'
7
+ require 'irb'
8
+ require 'well_rested'
9
+
10
+ #require File.dirname(__FILE__) + '/../spec/spec_helper'
11
+
12
+ # Enable request logging.
13
+ require 'restclient/components'
14
+ RestClient.enable Rack::CommonLogger
15
+
16
+ # Enable request caching via HTTP rules.
17
+ #require 'rack/cache'
18
+ #RestClient.enable Rack::Cache
19
+
20
+ include WellRested
21
+
22
+ @api = API.new
23
+
24
+ puts "\nWelcome to the WellRested command-line application. A default-configure WellRested::API instance is available in @api.\n\n"
25
+
26
+ IRB.start(__FILE__)
27
+
@@ -0,0 +1,29 @@
1
+ # HNSearch
2
+ # API access for news.ycombinator.com
3
+ module HNSearch
4
+ class Base < WellRested::Base
5
+ self.server = 'api.thriftdb.com/api.hnsearch.com'
6
+ end
7
+
8
+ class User < Base
9
+ self.path = '/users'
10
+
11
+ def items(api)
12
+ Item.search_items_by_username(api, self.username)
13
+ end
14
+ end
15
+
16
+ class Item < Base
17
+ self.path = '/items'
18
+
19
+ def self.search_items_by_username(api, username)
20
+ api.get("#{protocol}://#{server}/items/_search", :filter => { :fields => { :username => username } })
21
+ end
22
+ end
23
+
24
+ def self.your_author(api)
25
+ api.find(User, :id => 'nick_urban')
26
+ end
27
+ end
28
+
29
+
@@ -0,0 +1,17 @@
1
+ module GenericUtils
2
+ extend self
3
+
4
+ # Return a class object given its name.
5
+ def get_class(name)
6
+ Kernel.const_get(name)
7
+ rescue NameError
8
+ nil
9
+ end
10
+
11
+ # Return whether a class exists for a given name.
12
+ def class_exists?(name)
13
+ get_class(name) != nil
14
+ end
15
+
16
+ end
17
+
@@ -0,0 +1,43 @@
1
+
2
+ # This module is used to transform the keys found in resources between Rail's native underscore_case
3
+ # and the camelCase typically found in Java, etc.
4
+
5
+ module KeyTransformer
6
+ extend self
7
+
8
+ # Run through a hash or array of hashes and replace the keys with underscored versions.
9
+ # NOTE: Hash values may include simple values, other hashes or arrays, but Arrays may only include hashes.
10
+ # If we had an array of symbols (e.g. for permissions), we'd have to do this slightly differently
11
+ def underscore_keys(hash_or_array)
12
+ key_transform = Proc.new { |key| key.to_s.underscore }
13
+ transform_keys(hash_or_array, key_transform)
14
+ end
15
+
16
+ def camelize_keys(hash_or_array, upper_or_lower = :lower)
17
+ key_transform = Proc.new { |key| key.to_s.camelize(upper_or_lower) }
18
+ transform_keys(hash_or_array, key_transform)
19
+ end
20
+
21
+ # Takes a hash or array to process and a key transform (Proc),
22
+ # which should accept a key and return a transformed key.
23
+ # Returns a hash or array, depending on which was passed.
24
+ # NOTE: any objects which respond to 'attributes' (active record, active resource) will be turned into hashes.
25
+ # NOTE: all hashes are returned with indifferent access
26
+ def transform_keys(hash_or_array, key_transform)
27
+ if hash_or_array.is_a? Array
28
+ hash_or_array.map { |obj| transform_keys(obj, key_transform) }
29
+ elsif hash_or_array.is_a? Hash
30
+ new_hash = {}.with_indifferent_access
31
+ hash_or_array.each do |key, val|
32
+ new_hash[key_transform.call(key)] = transform_keys(val, key_transform)
33
+ end
34
+ new_hash
35
+ # Note: this case has been disabled because we now convert objects to hashes before passing them into underscore/camelize_keys.
36
+ # elsif hash_or_array.respond_to? :attributes # if this is an object rather than a hash / array, get the hash from its attributes
37
+ # transform_keys(hash_or_array.attributes, key_transform)
38
+ else
39
+ hash_or_array
40
+ end
41
+ end
42
+ end
43
+
@@ -0,0 +1,35 @@
1
+ # encoding: utf-8
2
+
3
+ # require external dependencies
4
+ require 'active_support/core_ext/hash/indifferent_access'
5
+ require 'active_support/core_ext/hash/reverse_merge'
6
+
7
+ # require internal general-use libs
8
+ require 'key_transformer'
9
+ require 'generic_utils'
10
+
11
+ # require internal libs
12
+ require 'well_rested/api'
13
+ require 'well_rested/base'
14
+ require 'well_rested/utils'
15
+ require 'well_rested/json_formatter'
16
+ require 'well_rested/camel_case_formatter'
17
+
18
+ # Make sure 'bases' singularizes to 'base' instead of 'basis'.
19
+ # Otherwise, we get an error that no class Basis is found in Base.
20
+ ActiveSupport::Inflector.inflections do |inflect|
21
+ inflect.irregular 'base', 'bases'
22
+ end
23
+
24
+ module WellRested
25
+ def logger
26
+ return Rails.logger if Utils.class_exists? 'Rails'
27
+ return @logger if @logger
28
+
29
+ require 'logger'
30
+ @logger = Logger.new(STDERR)
31
+ @logger.datetime_format = "%H:%M:%S"
32
+ @logger
33
+ end
34
+ end
35
+