couchrest 1.0.0.beta2 → 1.0.0.beta3

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.
data/Rakefile CHANGED
@@ -1,6 +1,8 @@
1
1
  require 'rake'
2
2
  require "rake/rdoctask"
3
- require File.join(File.expand_path(File.dirname(__FILE__)),'lib','couchrest')
3
+
4
+ $LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
5
+ require 'couchrest'
4
6
 
5
7
  begin
6
8
  require 'spec/rake/spectask'
@@ -25,7 +27,7 @@ begin
25
27
  gemspec.files = %w( LICENSE README.md Rakefile THANKS.md history.txt couchrest.gemspec) + Dir["{examples,lib,spec,utils}/**/*"] - Dir["spec/tmp"]
26
28
  gemspec.has_rdoc = true
27
29
  gemspec.add_dependency("rest-client", ">= 1.5.1")
28
- gemspec.add_dependency("json", "<= 1.4.2")
30
+ gemspec.add_dependency("json", "= 1.2.4") # json 1.4.3 has stack overflow issues!
29
31
  # gemspec.add_dependency("couchrest_extended_document", ">= 1.0.0")
30
32
  gemspec.version = CouchRest::VERSION
31
33
  gemspec.date = "2010-07-01"
@@ -65,4 +67,4 @@ module Rake
65
67
  end
66
68
 
67
69
  Rake.remove_task("github:release")
68
- Rake.remove_task("release")
70
+ Rake.remove_task("release")
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{couchrest}
8
- s.version = "1.0.0.beta2"
8
+ s.version = "1.0.0.beta3"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["J. Chris Anderson", "Matt Aimonetti", "Marcos Tapajos", "Will Leinweber"]
12
- s.date = %q{2010-07-01}
12
+ s.date = %q{2010-07-25}
13
13
  s.description = %q{CouchRest provides a simple interface on top of CouchDB's RESTful HTTP API, as well as including some utility scripts for managing views and attachments.}
14
14
  s.email = %q{jchris@apache.org}
15
15
  s.extra_rdoc_files = [
@@ -49,7 +49,7 @@ Gem::Specification.new do |s|
49
49
  "lib/couchrest/response.rb",
50
50
  "lib/couchrest/rest_api.rb",
51
51
  "lib/couchrest/server.rb",
52
- "lib/couchrest/support/class.rb",
52
+ "lib/couchrest/support/inheritable_attributes.rb",
53
53
  "spec/couchrest/couchrest_spec.rb",
54
54
  "spec/couchrest/database_spec.rb",
55
55
  "spec/couchrest/design_spec.rb",
@@ -95,14 +95,14 @@ Gem::Specification.new do |s|
95
95
 
96
96
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
97
97
  s.add_runtime_dependency(%q<rest-client>, [">= 1.5.1"])
98
- s.add_runtime_dependency(%q<json>, ["<= 1.4.2"])
98
+ s.add_runtime_dependency(%q<json>, ["= 1.2.4"])
99
99
  else
100
100
  s.add_dependency(%q<rest-client>, [">= 1.5.1"])
101
- s.add_dependency(%q<json>, ["<= 1.4.2"])
101
+ s.add_dependency(%q<json>, ["= 1.2.4"])
102
102
  end
103
103
  else
104
104
  s.add_dependency(%q<rest-client>, [">= 1.5.1"])
105
- s.add_dependency(%q<json>, ["<= 1.4.2"])
105
+ s.add_dependency(%q<json>, ["= 1.2.4"])
106
106
  end
107
107
  end
108
108
 
@@ -2,8 +2,12 @@
2
2
 
3
3
  * Major enhancements
4
4
  * Add create_target option to Database#replicate_to and #replicate_from. http://github.com/couchrest/couchrest/issues/#issue/26 (Alexander Uvarov)
5
+ * Removing unused core extensions and moving extlib_inhertiable_* methods to use couchrest_inheritable_*
6
+ to avoid conflicts with Rails. (Geoff Buesing)
5
7
 
6
8
  * Minor enhancements
9
+ * Added Document#id= support (issue detected by Rory Franklin with RSpec model stubs)
10
+ * Fixing issues with CouchDB 1.0 and RestClient
7
11
 
8
12
  == 1.0.0.beta
9
13
 
@@ -13,9 +13,11 @@
13
13
  # limitations under the License.
14
14
 
15
15
  require 'rubygems'
16
- gem 'json', "<= 1.4.2"
17
- require 'json'
18
16
  gem 'rest-client', ">= 1.5.1"
17
+ unless Kernel.const_defined?("JSON")
18
+ gem 'json', '1.2.4'
19
+ require 'json'
20
+ end
19
21
  require 'rest_client'
20
22
 
21
23
  # Not sure why this is required, so removed until a reason is found!
@@ -25,10 +27,11 @@ $:.unshift File.dirname(__FILE__) unless
25
27
 
26
28
  require 'couchrest/monkeypatches'
27
29
  require 'couchrest/rest_api'
30
+ require 'couchrest/support/inheritable_attributes'
28
31
 
29
32
  # = CouchDB, close to the metal
30
33
  module CouchRest
31
- VERSION = '1.0.0.beta2'
34
+ VERSION = '1.0.0.beta3'
32
35
 
33
36
  autoload :Server, 'couchrest/server'
34
37
  autoload :Database, 'couchrest/database'
@@ -134,4 +137,4 @@ class CouchRest::ExtendedDocument < CouchRest::Document
134
137
  raise "ExtendedDocument is no longer included in CouchRest base driver, see couchrest_extended_document gem"
135
138
  end
136
139
 
137
- end
140
+ end
@@ -65,7 +65,7 @@ module CouchRest
65
65
  keys = params.delete(:keys)
66
66
  funcs = funcs.merge({:keys => keys}) if keys
67
67
  url = CouchRest.paramify_url "#{@root}/_temp_view", params
68
- JSON.parse(RestClient.post(url, funcs.to_json, {"Content-Type" => 'application/json'}))
68
+ JSON.parse(RestClient.post(url, funcs.to_json, CouchRest.default_headers))
69
69
  end
70
70
 
71
71
  # backwards compatibility is a plus
@@ -108,14 +108,14 @@ module CouchRest
108
108
  # GET an attachment directly from CouchDB
109
109
  def fetch_attachment(doc, name)
110
110
  uri = url_for_attachment(doc, name)
111
- RestClient.get uri
111
+ RestClient.get uri, CouchRest.default_headers
112
112
  end
113
113
 
114
114
  # PUT an attachment directly to CouchDB
115
115
  def put_attachment(doc, name, file, options = {})
116
116
  docid = escape_docid(doc['_id'])
117
117
  uri = url_for_attachment(doc, name)
118
- JSON.parse(RestClient.put(uri, file, options))
118
+ JSON.parse(RestClient.put(uri, file, CouchRest.default_headers.merge(options)))
119
119
  end
120
120
 
121
121
  # DELETE an attachment directly from CouchDB
@@ -123,13 +123,13 @@ module CouchRest
123
123
  uri = url_for_attachment(doc, name)
124
124
  # this needs a rev
125
125
  begin
126
- JSON.parse(RestClient.delete(uri))
126
+ CouchRest.delete(uri)
127
127
  rescue Exception => error
128
128
  if force
129
129
  # get over a 409
130
130
  doc = get(doc['_id'])
131
131
  uri = url_for_attachment(doc, name)
132
- JSON.parse(RestClient.delete(uri))
132
+ CouchRest.delete(uri)
133
133
  else
134
134
  error
135
135
  end
@@ -18,7 +18,7 @@ module CouchRest
18
18
  doc_keys = keys.collect{|k|"doc['#{k}']"} # this is where :require => 'doc.x == true' would show up
19
19
  key_emit = doc_keys.length == 1 ? "#{doc_keys.first}" : "[#{doc_keys.join(', ')}]"
20
20
  guards = opts.delete(:guards) || []
21
- guards.concat doc_keys
21
+ guards += doc_keys.map{|k| "(#{k} != null)"}
22
22
  map_function = <<-JAVASCRIPT
23
23
  function(doc) {
24
24
  if (#{guards.join(' && ')}) {
@@ -3,8 +3,9 @@ require 'delegate'
3
3
  module CouchRest
4
4
  class Document < Response
5
5
  include CouchRest::Attachments
6
+ extend CouchRest::InheritableAttributes
6
7
 
7
- extlib_inheritable_accessor :database
8
+ couchrest_inheritable_accessor :database
8
9
  attr_accessor :database
9
10
 
10
11
  # override the CouchRest::Model-wide default_database
@@ -17,6 +18,10 @@ module CouchRest
17
18
  def id
18
19
  self['_id']
19
20
  end
21
+
22
+ def id=(id)
23
+ self['_id'] = id
24
+ end
20
25
 
21
26
  def rev
22
27
  self['_rev']
@@ -1,4 +1,3 @@
1
- require File.join(File.dirname(__FILE__), 'support', 'class')
2
1
  require 'timeout'
3
2
 
4
3
  # This file must be loaded after the JSON gem and any other library that beats up the Time class.
@@ -1,9 +1,16 @@
1
1
  module RestAPI
2
2
 
3
+ def default_headers
4
+ {
5
+ :content_type => :json,
6
+ :accept => :json
7
+ }
8
+ end
9
+
3
10
  def put(uri, doc = nil)
4
11
  payload = doc.to_json if doc
5
12
  begin
6
- JSON.parse(RestClient.put(uri, payload))
13
+ JSON.parse(RestClient.put(uri, payload, default_headers))
7
14
  rescue Exception => e
8
15
  if $DEBUG
9
16
  raise "Error while sending a PUT request #{uri}\npayload: #{payload.inspect}\n#{e}"
@@ -15,7 +22,7 @@ module RestAPI
15
22
 
16
23
  def get(uri)
17
24
  begin
18
- JSON.parse(RestClient.get(uri), :max_nesting => false)
25
+ JSON.parse(RestClient.get(uri, default_headers), :max_nesting => false)
19
26
  rescue => e
20
27
  if $DEBUG
21
28
  raise "Error while sending a GET request #{uri}\n: #{e}"
@@ -28,7 +35,7 @@ module RestAPI
28
35
  def post(uri, doc = nil)
29
36
  payload = doc.to_json if doc
30
37
  begin
31
- JSON.parse(RestClient.post(uri, payload))
38
+ JSON.parse(RestClient.post(uri, payload, default_headers))
32
39
  rescue Exception => e
33
40
  if $DEBUG
34
41
  raise "Error while sending a POST request #{uri}\npayload: #{payload.inspect}\n#{e}"
@@ -39,13 +46,13 @@ module RestAPI
39
46
  end
40
47
 
41
48
  def delete(uri)
42
- JSON.parse(RestClient.delete(uri))
49
+ JSON.parse(RestClient.delete(uri, default_headers))
43
50
  end
44
51
 
45
52
  def copy(uri, destination)
46
53
  JSON.parse(RestClient::Request.execute( :method => :copy,
47
54
  :url => uri,
48
- :headers => {'Destination' => destination}
55
+ :headers => default_headers.merge('Destination' => destination)
49
56
  ).to_s)
50
57
  end
51
58
 
@@ -73,6 +73,8 @@ module CouchRest
73
73
  # Restart the CouchDB instance
74
74
  def restart!
75
75
  CouchRest.post "#{@uri}/_restart"
76
+ rescue RestClient::ServerBrokeConnection
77
+ # Shouldn't really happen, but does in CouchDB 1.0.0
76
78
  end
77
79
 
78
80
  # Retrive an unused UUID from CouchDB. Server instances manage caching a list of unused UUIDs.
@@ -0,0 +1,107 @@
1
+ # Copyright (c) 2006-2009 David Heinemeier Hansson
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.
21
+ #
22
+ # Extracted From
23
+ # http://github.com/rails/rails/commit/971e2438d98326c994ec6d3ef8e37b7e868ed6e2
24
+
25
+ module CouchRest
26
+ module InheritableAttributes
27
+
28
+ # Defines class-level inheritable attribute reader. Attributes are available to subclasses,
29
+ # each subclass has a copy of parent's attribute.
30
+ #
31
+ # @param *syms<Array[#to_s]> Array of attributes to define inheritable reader for.
32
+ # @return <Array[#to_s]> Array of attributes converted into inheritable_readers.
33
+ #
34
+ # @api public
35
+ #
36
+ # @todo Do we want to block instance_reader via :instance_reader => false
37
+ # @todo It would be preferable that we do something with a Hash passed in
38
+ # (error out or do the same as other methods above) instead of silently
39
+ # moving on). In particular, this makes the return value of this function
40
+ # less useful.
41
+ def couchrest_inheritable_reader(*ivars)
42
+ instance_reader = ivars.pop[:reader] if ivars.last.is_a?(Hash)
43
+
44
+ ivars.each do |ivar|
45
+ self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
46
+ def self.#{ivar}
47
+ return @#{ivar} if self.object_id == #{self.object_id} || defined?(@#{ivar})
48
+ ivar = superclass.#{ivar}
49
+ return nil if ivar.nil? && !#{self}.instance_variable_defined?("@#{ivar}")
50
+ @#{ivar} = ivar && !ivar.is_a?(Module) && !ivar.is_a?(Numeric) && !ivar.is_a?(TrueClass) && !ivar.is_a?(FalseClass) ? ivar.dup : ivar
51
+ end
52
+ RUBY
53
+ unless instance_reader == false
54
+ self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
55
+ def #{ivar}
56
+ self.class.#{ivar}
57
+ end
58
+ RUBY
59
+ end
60
+ end
61
+ end
62
+
63
+ # Defines class-level inheritable attribute writer. Attributes are available to subclasses,
64
+ # each subclass has a copy of parent's attribute.
65
+ #
66
+ # @param *syms<Array[*#to_s, Hash{:instance_writer => Boolean}]> Array of attributes to
67
+ # define inheritable writer for.
68
+ # @option syms :instance_writer<Boolean> if true, instance-level inheritable attribute writer is defined.
69
+ # @return <Array[#to_s]> An Array of the attributes that were made into inheritable writers.
70
+ #
71
+ # @api public
72
+ #
73
+ # @todo We need a style for class_eval <<-HEREDOC. I'd like to make it
74
+ # class_eval(<<-RUBY, __FILE__, __LINE__), but we should codify it somewhere.
75
+ def couchrest_inheritable_writer(*ivars)
76
+ instance_writer = ivars.pop[:writer] if ivars.last.is_a?(Hash)
77
+ ivars.each do |ivar|
78
+ self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
79
+ def self.#{ivar}=(obj)
80
+ @#{ivar} = obj
81
+ end
82
+ RUBY
83
+ unless instance_writer == false
84
+ self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
85
+ def #{ivar}=(obj) self.class.#{ivar} = obj end
86
+ RUBY
87
+ end
88
+
89
+ self.send("#{ivar}=", yield) if block_given?
90
+ end
91
+ end
92
+
93
+ # Defines class-level inheritable attribute accessor. Attributes are available to subclasses,
94
+ # each subclass has a copy of parent's attribute.
95
+ #
96
+ # @param *syms<Array[*#to_s, Hash{:instance_writer => Boolean}]> Array of attributes to
97
+ # define inheritable accessor for.
98
+ # @option syms :instance_writer<Boolean> if true, instance-level inheritable attribute writer is defined.
99
+ # @return <Array[#to_s]> An Array of attributes turned into inheritable accessors.
100
+ #
101
+ # @api public
102
+ def couchrest_inheritable_accessor(*syms, &block)
103
+ couchrest_inheritable_reader(*syms)
104
+ couchrest_inheritable_writer(*syms, &block)
105
+ end
106
+ end
107
+ end
@@ -28,6 +28,13 @@ describe CouchRest do
28
28
 
29
29
  it "should restart" do
30
30
  @cr.restart!
31
+ begin
32
+ @cr.info
33
+ rescue
34
+ # Give the couchdb time to restart
35
+ sleep 0.2
36
+ retry
37
+ end
31
38
  end
32
39
 
33
40
  it "should provide one-time access to uuids" do
@@ -137,7 +144,7 @@ describe CouchRest do
137
144
 
138
145
  describe "ensuring the db exists" do
139
146
  it "should be super easy" do
140
- db = CouchRest.database! "http://127.0.0.1:5984/couchrest-test-2"
147
+ db = CouchRest.database! "#{COUCHHOST}/couchrest-test-2"
141
148
  db.name.should == 'couchrest-test-2'
142
149
  db.info["db_name"].should == 'couchrest-test-2'
143
150
  end
@@ -180,7 +180,7 @@ describe CouchRest::Database do
180
180
 
181
181
  docs = [{'key' => 'value'}, {'_id' => 'totally-uniq'}]
182
182
  id_docs = [{'key' => 'value', '_id' => 'asdf6sgadkfhgsdfusdf'}, {'_id' => 'totally-uniq'}]
183
- CouchRest.should_receive(:post).with("http://127.0.0.1:5984/couchrest-test/_bulk_docs", {:docs => id_docs})
183
+ CouchRest.should_receive(:post).with("#{COUCHHOST}/couchrest-test/_bulk_docs", {:docs => id_docs})
184
184
 
185
185
  @db.bulk_save(docs)
186
186
  end
@@ -761,14 +761,14 @@ describe CouchRest::Database do
761
761
 
762
762
  shared_examples_for "continuously replicated" do
763
763
  it "contains the document from the original database" do
764
- sleep(1) # Allow some time to replicate
764
+ sleep(1.5) # Allow some time to replicate
765
765
  doc = @other_db.get('test_doc')
766
766
  doc['some-value'].should == 'foo'
767
767
  end
768
768
 
769
769
  it "contains documents saved after replication initiated" do
770
770
  @db.save_doc({'_id' => 'test_doc_after', 'some-value' => 'bar'})
771
- sleep(1) # Allow some time to replicate
771
+ sleep(1.5) # Allow some time to replicate
772
772
  doc = @other_db.get('test_doc_after')
773
773
  doc['some-value'].should == 'bar'
774
774
  end
@@ -134,5 +134,25 @@ describe CouchRest::Design do
134
134
  res["rows"].first["key"].should == ["a",2]
135
135
  end
136
136
  end
137
-
137
+
138
+ describe "a view with nil and 0 values" do
139
+ before(:all) do
140
+ @db = reset_test_db!
141
+ @des = CouchRest::Design.new
142
+ @des.name = "test"
143
+ @des.view_by :code
144
+ @des.database = @db
145
+ @des.save
146
+ @db.bulk_save([{"code" => "a", "age" => 2},
147
+ {"code" => nil, "age" => 4},{"code" => 0, "age" => 9}])
148
+ end
149
+ it "should work" do
150
+ res = @des.view :by_code
151
+ res["rows"][0]["key"].should == 0
152
+ res["rows"][1]["key"].should == "a"
153
+ res["rows"][2].should be_nil
154
+ end
155
+ end
156
+
157
+
138
158
  end
@@ -62,6 +62,10 @@ describe CouchRest::Document do
62
62
  @doc.rev.should be_nil
63
63
  @doc.id.should be_nil
64
64
  end
65
+ it "should be possible to set id" do
66
+ @doc.id = 1
67
+ @doc.id.should eql(1)
68
+ end
65
69
 
66
70
  it "should freak out when saving without a database" do
67
71
  lambda{@doc.save}.should raise_error(ArgumentError)
@@ -4,7 +4,7 @@ describe CouchRest::Server do
4
4
 
5
5
  describe "available databases" do
6
6
  before(:each) do
7
- @couch = CouchRest::Server.new
7
+ @couch = CouchRest::Server.new COUCHHOST
8
8
  end
9
9
 
10
10
  after(:each) do
@@ -8,10 +8,10 @@ unless defined?(FIXTURE_PATH)
8
8
  FIXTURE_PATH = File.join(File.dirname(__FILE__), '/fixtures')
9
9
  SCRATCH_PATH = File.join(File.dirname(__FILE__), '/tmp')
10
10
 
11
- COUCHHOST = "http://127.0.0.1:5984"
11
+ COUCHHOST = ENV['COUCHHOST'] || "http://127.0.0.1:5984"
12
12
  TESTDB = 'couchrest-test'
13
13
  REPLICATIONDB = 'couchrest-test-replication'
14
- TEST_SERVER = CouchRest.new
14
+ TEST_SERVER = CouchRest.new COUCHHOST
15
15
  TEST_SERVER.default_database = TESTDB
16
16
  DB = TEST_SERVER.database(TESTDB)
17
17
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: couchrest
3
3
  version: !ruby/object:Gem::Version
4
- hash: -1848230054
4
+ hash: -1848230053
5
5
  prerelease: true
6
6
  segments:
7
7
  - 1
8
8
  - 0
9
9
  - 0
10
- - beta2
11
- version: 1.0.0.beta2
10
+ - beta3
11
+ version: 1.0.0.beta3
12
12
  platform: ruby
13
13
  authors:
14
14
  - J. Chris Anderson
@@ -19,7 +19,7 @@ autorequire:
19
19
  bindir: bin
20
20
  cert_chain: []
21
21
 
22
- date: 2010-07-01 00:00:00 -03:00
22
+ date: 2010-07-25 00:00:00 -03:00
23
23
  default_executable:
24
24
  dependencies:
25
25
  - !ruby/object:Gem::Dependency
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirement: &id002 !ruby/object:Gem::Requirement
45
45
  none: false
46
46
  requirements:
47
- - - <=
47
+ - - "="
48
48
  - !ruby/object:Gem::Version
49
- hash: 3
49
+ hash: 23
50
50
  segments:
51
51
  - 1
52
- - 4
53
52
  - 2
54
- version: 1.4.2
53
+ - 4
54
+ version: 1.2.4
55
55
  type: :runtime
56
56
  version_requirements: *id002
57
57
  description: CouchRest provides a simple interface on top of CouchDB's RESTful HTTP API, as well as including some utility scripts for managing views and attachments.
@@ -96,7 +96,7 @@ files:
96
96
  - lib/couchrest/response.rb
97
97
  - lib/couchrest/rest_api.rb
98
98
  - lib/couchrest/server.rb
99
- - lib/couchrest/support/class.rb
99
+ - lib/couchrest/support/inheritable_attributes.rb
100
100
  - spec/couchrest/couchrest_spec.rb
101
101
  - spec/couchrest/database_spec.rb
102
102
  - spec/couchrest/design_spec.rb
@@ -1,190 +0,0 @@
1
- # Copyright (c) 2006-2009 David Heinemeier Hansson
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.
21
- #
22
- # Extracted From
23
- # http://github.com/rails/rails/commit/971e2438d98326c994ec6d3ef8e37b7e868ed6e2
24
-
25
- # Extends the class object with class and instance accessors for class attributes,
26
- # just like the native attr* accessors for instance attributes.
27
- #
28
- # class Person
29
- # cattr_accessor :hair_colors
30
- # end
31
- #
32
- # Person.hair_colors = [:brown, :black, :blonde, :red]
33
- class Class
34
- def cattr_reader(*syms)
35
- syms.flatten.each do |sym|
36
- next if sym.is_a?(Hash)
37
- class_eval(<<-EOS, __FILE__, __LINE__ + 1)
38
- unless defined? @@#{sym} # unless defined? @@hair_colors
39
- @@#{sym} = nil # @@hair_colors = nil
40
- end # end
41
- #
42
- def self.#{sym} # def self.hair_colors
43
- @@#{sym} # @@hair_colors
44
- end # end
45
- #
46
- def #{sym} # def hair_colors
47
- @@#{sym} # @@hair_colors
48
- end # end
49
- EOS
50
- end
51
- end unless Class.respond_to?(:cattr_reader)
52
-
53
- def cattr_writer(*syms)
54
- options = syms.extract_options!
55
- syms.flatten.each do |sym|
56
- class_eval(<<-EOS, __FILE__, __LINE__ + 1)
57
- unless defined? @@#{sym} # unless defined? @@hair_colors
58
- @@#{sym} = nil # @@hair_colors = nil
59
- end # end
60
- #
61
- def self.#{sym}=(obj) # def self.hair_colors=(obj)
62
- @@#{sym} = obj # @@hair_colors = obj
63
- end # end
64
- #
65
- #{" #
66
- def #{sym}=(obj) # def hair_colors=(obj)
67
- @@#{sym} = obj # @@hair_colors = obj
68
- end # end
69
- " unless options[:instance_writer] == false } # # instance writer above is generated unless options[:instance_writer] == false
70
- EOS
71
- end
72
- end unless Class.respond_to?(:cattr_writer)
73
-
74
- def cattr_accessor(*syms)
75
- cattr_reader(*syms)
76
- cattr_writer(*syms)
77
- end unless Class.respond_to?(:cattr_accessor)
78
-
79
- # Defines class-level inheritable attribute reader. Attributes are available to subclasses,
80
- # each subclass has a copy of parent's attribute.
81
- #
82
- # @param *syms<Array[#to_s]> Array of attributes to define inheritable reader for.
83
- # @return <Array[#to_s]> Array of attributes converted into inheritable_readers.
84
- #
85
- # @api public
86
- #
87
- # @todo Do we want to block instance_reader via :instance_reader => false
88
- # @todo It would be preferable that we do something with a Hash passed in
89
- # (error out or do the same as other methods above) instead of silently
90
- # moving on). In particular, this makes the return value of this function
91
- # less useful.
92
- def extlib_inheritable_reader(*ivars)
93
- instance_reader = ivars.pop[:reader] if ivars.last.is_a?(Hash)
94
-
95
- ivars.each do |ivar|
96
- self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
97
- def self.#{ivar}
98
- return @#{ivar} if self.object_id == #{self.object_id} || defined?(@#{ivar})
99
- ivar = superclass.#{ivar}
100
- return nil if ivar.nil? && !#{self}.instance_variable_defined?("@#{ivar}")
101
- @#{ivar} = ivar && !ivar.is_a?(Module) && !ivar.is_a?(Numeric) && !ivar.is_a?(TrueClass) && !ivar.is_a?(FalseClass) ? ivar.dup : ivar
102
- end
103
- RUBY
104
- unless instance_reader == false
105
- self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
106
- def #{ivar}
107
- self.class.#{ivar}
108
- end
109
- RUBY
110
- end
111
- end
112
- end unless Class.respond_to?(:extlib_inheritable_reader)
113
-
114
- # Defines class-level inheritable attribute writer. Attributes are available to subclasses,
115
- # each subclass has a copy of parent's attribute.
116
- #
117
- # @param *syms<Array[*#to_s, Hash{:instance_writer => Boolean}]> Array of attributes to
118
- # define inheritable writer for.
119
- # @option syms :instance_writer<Boolean> if true, instance-level inheritable attribute writer is defined.
120
- # @return <Array[#to_s]> An Array of the attributes that were made into inheritable writers.
121
- #
122
- # @api public
123
- #
124
- # @todo We need a style for class_eval <<-HEREDOC. I'd like to make it
125
- # class_eval(<<-RUBY, __FILE__, __LINE__), but we should codify it somewhere.
126
- def extlib_inheritable_writer(*ivars)
127
- instance_writer = ivars.pop[:writer] if ivars.last.is_a?(Hash)
128
- ivars.each do |ivar|
129
- self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
130
- def self.#{ivar}=(obj)
131
- @#{ivar} = obj
132
- end
133
- RUBY
134
- unless instance_writer == false
135
- self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
136
- def #{ivar}=(obj) self.class.#{ivar} = obj end
137
- RUBY
138
- end
139
-
140
- self.send("#{ivar}=", yield) if block_given?
141
- end
142
- end unless Class.respond_to?(:extlib_inheritable_writer)
143
-
144
- # Defines class-level inheritable attribute accessor. Attributes are available to subclasses,
145
- # each subclass has a copy of parent's attribute.
146
- #
147
- # @param *syms<Array[*#to_s, Hash{:instance_writer => Boolean}]> Array of attributes to
148
- # define inheritable accessor for.
149
- # @option syms :instance_writer<Boolean> if true, instance-level inheritable attribute writer is defined.
150
- # @return <Array[#to_s]> An Array of attributes turned into inheritable accessors.
151
- #
152
- # @api public
153
- def extlib_inheritable_accessor(*syms, &block)
154
- extlib_inheritable_reader(*syms)
155
- extlib_inheritable_writer(*syms, &block)
156
- end unless Class.respond_to?(:extlib_inheritable_accessor)
157
- end
158
-
159
- class Array
160
- # Extracts options from a set of arguments. Removes and returns the last
161
- # element in the array if it's a hash, otherwise returns a blank hash.
162
- #
163
- # def options(*args)
164
- # args.extract_options!
165
- # end
166
- #
167
- # options(1, 2) # => {}
168
- # options(1, 2, :a => :b) # => {:a=>:b}
169
- def extract_options!
170
- last.is_a?(::Hash) ? pop : {}
171
- end unless Array.new.respond_to?(:extract_options!)
172
-
173
- # Wraps the object in an Array unless it's an Array. Converts the
174
- # object to an Array using #to_ary if it implements that.
175
- def self.wrap(object)
176
- case object
177
- when nil
178
- []
179
- when self
180
- object
181
- else
182
- if object.respond_to?(:to_ary)
183
- object.to_ary
184
- else
185
- [object]
186
- end
187
- end
188
- end unless Array.respond_to?(:wrap)
189
- end
190
-