cmis-ruby 0.4.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 54d939c76212d26bf61e62941fc9c8befd44bd32
4
- data.tar.gz: a46f072f12e9309b00334e1c184c9250fd887539
3
+ metadata.gz: 3fefeee566f1ed7d06b802fe303f25b0dca90680
4
+ data.tar.gz: 02ed43827b5019697f254b7ebc1fe1ed9b26f00a
5
5
  SHA512:
6
- metadata.gz: c369361121888cbd294e8c897b153b677377dc115fb31924d46e25cd3c4eb9e24ffdba3081c13a95be8ebf4d490504264b3942febaaade37d43eb10e07f4cb21
7
- data.tar.gz: 5c8d73ce97ec3a0b873825e8cb9c1247c9b3ef3529469d03182da7d96a83627a7424003f901d3dd560d7b92a51171eed936227ad0c26072897888857acfd393e
6
+ metadata.gz: ac6b9a79e134b783db1fdc7a87ec914cfb9e3719dcd56ffbe2c95e29fc355fc6f6da8288b1d0f281cf35b50d4df4da7feedeea42288dfbcf95a21d31fb124720
7
+ data.tar.gz: f90b18091fd8c2759e492c524561a75dfc70d50fcdf7adb49cf6561c65c13e14025338987851619fe44825a211618cf435a86d5da4c061e8b9f53b1932e84260
data/.travis.yml CHANGED
@@ -1,6 +1,11 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 1.9.3
4
- - 2.0.0
3
+ - 2.0.0
4
+ # - 1.9.3
5
+ # - 2.1.0
5
6
  env:
6
- - TEST_ENV=alfresco
7
+ matrix:
8
+ - TEST_ENV=ci
9
+ global:
10
+ - secure: PwEKZ/1SJmQQzWeGa1y7EKkIHbfcPrM2jalmCYdPcmJ8Yyp0t/0PbRXmc75QRBjFwkkGo/q1kyfdAImAtqmnTEMToaxoDAJw+DbSjbhN1n3e7heD5eFjaqUtUVZsf1LKR6cXO/L6ZdeNBcQwwlbwN+8I5QJjW0NJGADME+zerP0=
11
+ - secure: SJRgR4WQzUisGk2Og18WbIsfqRCTIctUVjyEGPptYtLtEVo18A3O46MUZAlm6vyHAMpdq+u35KRw2xdJh7hkYg5yTp6jZG0aziDlhiNn6eOUaH/VZ/xBIZiSj+ceFxaq1G4UjfQnxJMqoadsjhApnNE2iQkgme5izXqmLY0e3tc=
data/cmis-ruby.gemspec CHANGED
@@ -20,7 +20,6 @@ Gem::Specification.new do |s|
20
20
  s.required_ruby_version = '>= 1.9.3'
21
21
 
22
22
  s.add_dependency 'faraday', '~> 0.9'
23
- s.add_dependency 'activesupport', '>= 3.2', '< 5.0'
24
23
 
25
24
  s.description = <<-DESCRIPTION
26
25
  CMIS browser binding client library in ruby.
data/lib/cmis-ruby.rb CHANGED
@@ -1,6 +1,3 @@
1
- require 'active_support/core_ext'
2
- require 'core_ext'
3
-
4
1
  require 'cmis/exceptions'
5
2
  require 'cmis/helpers'
6
3
  require 'cmis/object_factory'
data/lib/cmis/children.rb CHANGED
@@ -1,12 +1,14 @@
1
1
  require 'bigdecimal'
2
2
  require 'cmis/query_result'
3
+ require 'core_ext/hash/keys'
4
+ require 'core_ext/hash/slice'
3
5
 
4
6
  module CMIS
5
7
  class Children
6
8
  # Options: from, page_size
7
9
  def initialize(folder, options = {})
8
10
  @folder = folder
9
- @options = options.stringify_keys!
11
+ @options = options.symbolize_keys
10
12
 
11
13
  init_options
12
14
  end
@@ -64,19 +66,19 @@ module CMIS
64
66
  private
65
67
 
66
68
  def init_options
67
- @max_items = @options['page_size'] || 10
68
- @skip_count = @options['from'] || 0
69
- @order_by = @options['order_by']
70
- @filter = @options['filter']
71
- @include_relationships = @options['include_relationships']
69
+ @max_items = @options[:page_size] || 10
70
+ @skip_count = @options[:from] || 0
71
+ @order_by = @options[:order_by]
72
+ @filter = @options[:filter]
73
+ @include_relationships = @options[:include_relationships]
72
74
  @has_next = true
73
75
 
74
- @opts = @options.slice('query', 'headers')
76
+ @opts = @options.slice(:query, :headers)
75
77
  end
76
78
 
77
79
  def parse_limit(options)
78
- options.stringify_keys!
79
- limit = options['limit'] || 10
80
+ options.symbolize_keys!
81
+ limit = options[:limit] || 10
80
82
  limit = BigDecimal::INFINITY if limit == :all
81
83
  raise 'Not a valid limit' unless limit.is_a? Numeric
82
84
  limit
@@ -1,8 +1,10 @@
1
- require 'faraday'
2
- require 'cmis/version'
3
- require 'cmis/connection/url_resolver'
4
1
  require 'cmis/connection/request_modifier'
5
2
  require 'cmis/connection/response_parser'
3
+ require 'cmis/connection/url_resolver'
4
+ require 'cmis/version'
5
+ require 'core_ext/hash/compact'
6
+ require 'core_ext/hash/keys'
7
+ require 'faraday'
6
8
 
7
9
  module CMIS
8
10
  class Connection
@@ -37,6 +39,7 @@ module CMIS
37
39
  end
38
40
 
39
41
  def execute!(params = {}, options = {})
42
+ params.symbolize_keys!
40
43
  options.symbolize_keys!
41
44
 
42
45
  query = options[:query] || {}
@@ -1,3 +1,4 @@
1
+ require 'core_ext/hash/compact'
1
2
  require 'faraday'
2
3
 
3
4
  module CMIS
@@ -1,31 +1,42 @@
1
+ require 'core_ext/array/indifferent_access'
2
+ require 'core_ext/hash/indifferent_access'
1
3
  require 'faraday'
2
4
  require 'json'
3
5
 
4
6
  module CMIS
5
7
  class Connection
6
8
  class ResponseParser < Faraday::Middleware
7
- JSON_CONTENT_TYPE = /\/(x-)?json(;.+?)?$/
9
+ JSON_CONTENT_TYPE = /\/(x-)?json(;.+?)?$/i.freeze
8
10
 
9
11
  def call(env)
10
12
  @app.call(env).on_complete do |env|
11
- if env[:response_headers][:content_type] =~ JSON_CONTENT_TYPE
12
- env[:body] = JSON.parse(env[:body]).with_indifferent_access
13
- check_for_exception!(env[:body])
13
+ case env[:status]
14
+ when 401
15
+ raise Exceptions::Unauthorized
16
+ else
17
+ if env[:response_headers][:content_type] =~ JSON_CONTENT_TYPE
18
+ env[:body] = JSON.parse(env[:body]).with_indifferent_access
19
+ check_for_cmis_exception!(env[:body])
20
+ end
14
21
  end
15
22
  end
16
23
  end
17
24
 
18
25
  private
19
26
 
20
- def check_for_exception!(body)
27
+ def check_for_cmis_exception!(body)
21
28
  return unless body.is_a?(Hash)
22
29
 
23
- if ex = body[:exception]
24
- ruby_exception = "CMIS::Exceptions::#{ex.camelize}".constantize
25
- message = "#{ex.underscore.humanize}: #{body[:message]}"
26
- raise ruby_exception, message
30
+ if exception = body[:exception]
31
+ raise exception_class(exception), "#{exception}: #{body[:message]}"
27
32
  end
28
33
  end
34
+
35
+ def exception_class(exception)
36
+ clazz = exception.dup
37
+ clazz[0] = clazz[0].upcase
38
+ CMIS::Exceptions.const_get(clazz)
39
+ end
29
40
  end
30
41
  end
31
42
  end
@@ -4,34 +4,22 @@ module CMIS
4
4
  def initialize(http, service_url)
5
5
  @http = http
6
6
  @service_url = service_url
7
- @cache = {}
7
+ @repository_infos = {}
8
8
  end
9
9
 
10
10
  def url(repository_id, object_id)
11
- return @service_url if repository_id.nil?
11
+ return @service_url unless repository_id
12
12
 
13
- urls = repository_urls(repository_id)
14
- urls[object_id ? :root_folder_url : :repository_url]
15
- end
16
-
17
- private
18
-
19
- def repository_urls(repository_id)
20
- if @cache[repository_id].nil?
21
- repository_infos = @http.get(@service_url).body
22
-
23
- unless repository_infos.has_key?(repository_id)
24
- raise Exceptions::ObjectNotFound, "repositoryId: #{repository_id}"
25
- end
26
-
27
- repository_info = repository_infos[repository_id]
28
- @cache[repository_id] = {
29
- repository_url: repository_info[:repositoryUrl],
30
- root_folder_url: repository_info[:rootFolderUrl]
31
- }
13
+ unless @repository_infos.key?(repository_id)
14
+ @repository_infos = @http.get(@service_url).body
32
15
  end
33
16
 
34
- @cache[repository_id]
17
+ if @repository_infos.key?(repository_id)
18
+ key = object_id ? 'rootFolderUrl' : 'repositoryUrl'
19
+ @repository_infos[repository_id][key]
20
+ else
21
+ raise Exceptions::ObjectNotFound, "repositoryId: #{repository_id}"
22
+ end
35
23
  end
36
24
  end
37
25
  end
data/lib/cmis/document.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'core_ext/hash/keys'
2
+
1
3
  module CMIS
2
4
  class Document < Object
3
5
  def initialize(raw, repository)
@@ -46,10 +48,10 @@ module CMIS
46
48
  end
47
49
 
48
50
  def content=(opts = {})
49
- opts.stringify_keys!
50
- content = { stream: opts.delete('stream'),
51
- mime_type: opts.delete('mime_type'),
52
- filename: opts.delete('filename') }
51
+ opts.symbolize_keys!
52
+ content = { stream: opts.delete(:stream),
53
+ mime_type: opts.delete(:mime_type),
54
+ filename: opts.delete(:filename) }
53
55
 
54
56
  if content[:stream].is_a? String
55
57
  content[:stream] = StringIO.new(content[:stream])
@@ -13,5 +13,8 @@ module CMIS
13
13
  class StreamNotSupported < Exception; end
14
14
  class UpdateConflict < Exception; end
15
15
  class Versioning < Exception; end
16
+
17
+ # Non-CMIS
18
+ class Unauthorized < Exception; end
16
19
  end
17
20
  end
data/lib/cmis/helpers.rb CHANGED
@@ -1,3 +1,6 @@
1
+ require 'core_ext/hash/indifferent_access'
2
+ require 'core_ext/string/underscore'
3
+
1
4
  module CMIS
2
5
  module Helpers
3
6
  def initialize_properties(raw)
@@ -7,8 +10,8 @@ module CMIS
7
10
  def cmis_properties(properties)
8
11
  properties.each do |property_name|
9
12
  method_name = method_name(property_name)
10
- class_eval "def #{method_name};@properties['#{property_name}'];end"
11
- class_eval "def #{method_name}=(value);@properties['#{property_name}']=value;end"
13
+ self.class.class_eval "def #{method_name};@properties['#{property_name}'];end"
14
+ self.class.class_eval "def #{method_name}=(value);@properties['#{property_name}']=value;end"
12
15
  end
13
16
  end
14
17
 
@@ -50,8 +53,6 @@ module CMIS
50
53
  end
51
54
 
52
55
  def get_properties_map(raw)
53
- raw = raw.with_indifferent_access
54
-
55
56
  if raw['succinctProperties']
56
57
  result = raw['succinctProperties']
57
58
  elsif raw['properties']
@@ -1,11 +1,14 @@
1
+ require 'core_ext/hash/indifferent_access'
2
+ require 'core_ext/string/underscore'
3
+
1
4
  module CMIS
2
5
  class PropertyDefinition
3
6
  def initialize(hash = {})
4
7
  @hash = hash.with_indifferent_access
5
8
 
6
9
  @hash.each_key do |key|
7
- class_eval "def #{key.underscore};@hash['#{key}'];end"
8
- class_eval "def #{key.underscore}=(value);@hash['#{key}']=value;end"
10
+ self.class.class_eval "def #{key.underscore};@hash['#{key}'];end"
11
+ self.class.class_eval "def #{key.underscore}=(value);@hash['#{key}']=value;end"
9
12
  end
10
13
  end
11
14
 
data/lib/cmis/query.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  require 'bigdecimal'
2
2
  require 'cmis/query_result'
3
+ require 'core_ext/hash/keys'
4
+ require 'core_ext/hash/slice'
3
5
 
4
6
  module CMIS
5
7
  class Query
@@ -7,7 +9,7 @@ module CMIS
7
9
  def initialize(repository, statement, options = {})
8
10
  @repository = repository
9
11
  @statement = statement
10
- @options = options.stringify_keys
12
+ @options = options.symbolize_keys
11
13
 
12
14
  init_options
13
15
  end
@@ -65,17 +67,17 @@ module CMIS
65
67
  private
66
68
 
67
69
  def init_options
68
- @method = (@options['method'] || 'get').to_s.downcase
69
- @max_items = @options['page_size'] || 10
70
- @skip_count = @options['from'] || 0
70
+ @method = (@options[:method] || 'get').to_s.downcase
71
+ @max_items = @options[:page_size] || 10
72
+ @skip_count = @options[:from] || 0
71
73
  @has_next = true
72
74
 
73
- @opts = @options.slice('query', 'headers')
75
+ @opts = @options.slice(:query, :headers)
74
76
  end
75
77
 
76
78
  def parse_limit(options)
77
- options.stringify_keys!
78
- limit = options['limit'] || 10
79
+ options.symbolize_keys!
80
+ limit = options[:limit] || 10
79
81
  limit = BigDecimal::INFINITY if limit == :all
80
82
  raise 'Not a valid limit' unless limit.is_a? Numeric
81
83
  limit
@@ -1,12 +1,14 @@
1
1
  require 'bigdecimal'
2
2
  require 'cmis/query_result'
3
+ require 'core_ext/hash/keys'
4
+ require 'core_ext/hash/slice'
3
5
 
4
6
  module CMIS
5
7
  class Relationships
6
8
  # Options: from, page_size
7
9
  def initialize(object, options = {})
8
10
  @object = object
9
- @options = options.stringify_keys!
11
+ @options = options.symbolize_keys
10
12
 
11
13
  init_options
12
14
  end
@@ -64,19 +66,19 @@ module CMIS
64
66
  private
65
67
 
66
68
  def init_options
67
- @max_items = @options['page_size'] || 10
68
- @skip_count = @options['from'] || 0
69
- @direction = @options['direction'] || :either
70
- @include_subtypes = @options['include_subtypes']
71
- @type_id = @options['type_id']
69
+ @max_items = @options[:page_size] || 10
70
+ @skip_count = @options[:from] || 0
71
+ @direction = @options[:direction] || :either
72
+ @include_subtypes = @options[:include_subtypes]
73
+ @type_id = @options[:type_id]
72
74
  @has_next = true
73
75
 
74
- @opts = @options.slice('query', 'headers')
76
+ @opts = @options.slice(:query, :headers)
75
77
  end
76
78
 
77
79
  def parse_limit(options)
78
- options.stringify_keys!
79
- limit = options['limit'] || 10
80
+ options.symbolize_keys!
81
+ limit = options[:limit] || 10
80
82
  limit = BigDecimal::INFINITY if limit == :all
81
83
  raise 'Not a valid limit' unless limit.is_a? Numeric
82
84
  limit
@@ -1,5 +1,6 @@
1
- require 'json'
2
1
  require 'cmis/query'
2
+ require 'core_ext/string/underscore'
3
+ require 'json'
3
4
 
4
5
  module CMIS
5
6
  class Repository
@@ -8,8 +9,8 @@ module CMIS
8
9
  def initialize(raw, server)
9
10
  @hash = raw
10
11
  @hash.each_key do |key|
11
- class_eval "def #{key.underscore};@hash['#{key}'];end"
12
- class_eval "def #{key.gsub('repository', '').underscore};@hash['#{key}'];end" if key =~ /^repository/
12
+ self.class.class_eval "def #{key.underscore};@hash['#{key}'];end"
13
+ self.class.class_eval "def #{key.gsub('repository', '').underscore};@hash['#{key}'];end" if key =~ /^repository/
13
14
  end
14
15
 
15
16
  @server = server
@@ -106,15 +107,27 @@ module CMIS
106
107
  Query.new(self, statement, opts)
107
108
  end
108
109
 
109
- def find_object(type_id, properties, opts = {})
110
- clause = properties.map { |k, v| "#{k}=#{normalize(v)}" }.join(' and ')
111
- statement = "select * from #{type_id} where #{clause}"
110
+ def find_object(type_id, properties = {}, opts = {})
112
111
  opts.merge!(page_size: 1)
112
+ statement = construct_statement(type_id, properties)
113
113
  query(statement, opts).results.first
114
114
  end
115
115
 
116
+ def count_objects(type_id, properties = {}, opts = {})
117
+ opts.merge!(page_size: 0)
118
+ statement = construct_statement(type_id, properties)
119
+ query(statement, opts).total
120
+ end
121
+
116
122
  private
117
123
 
124
+ def construct_statement(type_id, properties)
125
+ statement = "select * from #{type_id}"
126
+ clause = properties.map { |k, v| "#{k}=#{normalize(v)}" }.join(' and ')
127
+ statement << " where #{clause}" unless clause.empty?
128
+ statement
129
+ end
130
+
118
131
  BACKSLASH = "\\"
119
132
  QUOTE = "\'"
120
133
 
data/lib/cmis/type.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'core_ext/hash/indifferent_access'
2
+ require 'core_ext/string/underscore'
1
3
  require 'json'
2
4
 
3
5
  module CMIS
@@ -15,11 +17,11 @@ module CMIS
15
17
  contentStreamAllowed allowedSourceTypes allowedTargetTypes )
16
18
 
17
19
  properties.each do |key|
18
- class_eval "def #{key.underscore};@hash['#{key}'];end"
19
- class_eval "def #{key.underscore}=(value);@hash['#{key}']=value;end"
20
+ self.class.class_eval "def #{key.underscore};@hash['#{key}'];end"
21
+ self.class.class_eval "def #{key.underscore}=(value);@hash['#{key}']=value;end"
20
22
  end
21
23
 
22
- @hash['propertyDefinitions'] ||= ActiveSupport::HashWithIndifferentAccess.new
24
+ @hash['propertyDefinitions'] ||= HashWithIndifferentAccess.new
23
25
  @hash['propertyDefinitions'].each do |key, value|
24
26
  @hash['propertyDefinitions'][key] = PropertyDefinition.new(value)
25
27
  end
data/lib/cmis/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module CMIS
2
- VERSION = '0.4.0'
2
+ VERSION = '0.4.1'
3
3
  end
@@ -1,5 +1,3 @@
1
- # Added in active_support 4.1
2
-
3
1
  class Hash
4
2
  # Returns a hash with non +nil+ values.
5
3
  #
@@ -0,0 +1,288 @@
1
+ require 'core_ext/hash/keys'
2
+
3
+ # Implements a hash where keys <tt>:foo</tt> and <tt>"foo"</tt> are considered
4
+ # to be the same.
5
+ #
6
+ # rgb = HashWithIndifferentAccess.new
7
+ #
8
+ # rgb[:black] = '#000000'
9
+ # rgb[:black] # => '#000000'
10
+ # rgb['black'] # => '#000000'
11
+ #
12
+ # rgb['white'] = '#FFFFFF'
13
+ # rgb[:white] # => '#FFFFFF'
14
+ # rgb['white'] # => '#FFFFFF'
15
+ #
16
+ # Internally symbols are mapped to strings when used as keys in the entire
17
+ # writing interface (calling <tt>[]=</tt>, <tt>merge</tt>, etc). This
18
+ # mapping belongs to the public interface. For example, given:
19
+ #
20
+ # hash = HashWithIndifferentAccess.new(a: 1)
21
+ #
22
+ # You are guaranteed that the key is returned as a string:
23
+ #
24
+ # hash.keys # => ["a"]
25
+ #
26
+ # Technically other types of keys are accepted:
27
+ #
28
+ # hash = HashWithIndifferentAccess.new(a: 1)
29
+ # hash[0] = 0
30
+ # hash # => {"a"=>1, 0=>0}
31
+ #
32
+ # but this class is intended for use cases where strings or symbols are the
33
+ # expected keys and it is convenient to understand both as the same. For
34
+ # example the +params+ hash in Ruby on Rails.
35
+ #
36
+ # Note that core extensions define <tt>Hash#with_indifferent_access</tt>:
37
+ #
38
+ # rgb = { black: '#000000', white: '#FFFFFF' }.with_indifferent_access
39
+ #
40
+ # which may be handy.
41
+ class HashWithIndifferentAccess < Hash
42
+ # Returns +true+ so that <tt>Array#extract_options!</tt> finds members of
43
+ # this class.
44
+ def extractable_options?
45
+ true
46
+ end
47
+
48
+ def with_indifferent_access
49
+ dup
50
+ end
51
+
52
+ def nested_under_indifferent_access
53
+ self
54
+ end
55
+
56
+ def initialize(constructor = {})
57
+ if constructor.is_a?(Hash)
58
+ super()
59
+ update(constructor)
60
+ else
61
+ super(constructor)
62
+ end
63
+ end
64
+
65
+ def default(key = nil)
66
+ if key.is_a?(Symbol) && include?(key = key.to_s)
67
+ self[key]
68
+ else
69
+ super
70
+ end
71
+ end
72
+
73
+ def self.new_from_hash_copying_default(hash)
74
+ new(hash).tap do |new_hash|
75
+ new_hash.default = hash.default
76
+ end
77
+ end
78
+
79
+ def self.[](*args)
80
+ new.merge!(Hash[*args])
81
+ end
82
+
83
+ alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
84
+ alias_method :regular_update, :update unless method_defined?(:regular_update)
85
+
86
+ # Assigns a new value to the hash:
87
+ #
88
+ # hash = HashWithIndifferentAccess.new
89
+ # hash[:key] = 'value'
90
+ #
91
+ # This value can be later fetched using either +:key+ or +'key'+.
92
+ def []=(key, value)
93
+ regular_writer(convert_key(key), convert_value(value, for: :assignment))
94
+ end
95
+
96
+ alias_method :store, :[]=
97
+
98
+ # Updates the receiver in-place, merging in the hash passed as argument:
99
+ #
100
+ # hash_1 = HashWithIndifferentAccess.new
101
+ # hash_1[:key] = 'value'
102
+ #
103
+ # hash_2 = HashWithIndifferentAccess.new
104
+ # hash_2[:key] = 'New Value!'
105
+ #
106
+ # hash_1.update(hash_2) # => {"key"=>"New Value!"}
107
+ #
108
+ # The argument can be either an
109
+ # <tt>HashWithIndifferentAccess</tt> or a regular +Hash+.
110
+ # In either case the merge respects the semantics of indifferent access.
111
+ #
112
+ # If the argument is a regular hash with keys +:key+ and +"key"+ only one
113
+ # of the values end up in the receiver, but which one is unspecified.
114
+ #
115
+ # When given a block, the value for duplicated keys will be determined
116
+ # by the result of invoking the block with the duplicated key, the value
117
+ # in the receiver, and the value in +other_hash+. The rules for duplicated
118
+ # keys follow the semantics of indifferent access:
119
+ #
120
+ # hash_1[:key] = 10
121
+ # hash_2['key'] = 12
122
+ # hash_1.update(hash_2) { |key, old, new| old + new } # => {"key"=>22}
123
+ def update(other_hash)
124
+ if other_hash.is_a? HashWithIndifferentAccess
125
+ super(other_hash)
126
+ else
127
+ other_hash.each_pair do |key, value|
128
+ if block_given? && key?(key)
129
+ value = yield(convert_key(key), self[key], value)
130
+ end
131
+ regular_writer(convert_key(key), convert_value(value))
132
+ end
133
+ self
134
+ end
135
+ end
136
+
137
+ alias_method :merge!, :update
138
+
139
+ # Checks the hash for a key matching the argument passed in:
140
+ #
141
+ # hash = HashWithIndifferentAccess.new
142
+ # hash['key'] = 'value'
143
+ # hash.key?(:key) # => true
144
+ # hash.key?('key') # => true
145
+ def key?(key)
146
+ super(convert_key(key))
147
+ end
148
+
149
+ alias_method :include?, :key?
150
+ alias_method :has_key?, :key?
151
+ alias_method :member?, :key?
152
+
153
+ # Same as <tt>Hash#fetch</tt> where the key passed as argument can be
154
+ # either a string or a symbol:
155
+ #
156
+ # counters = HashWithIndifferentAccess.new
157
+ # counters[:foo] = 1
158
+ #
159
+ # counters.fetch('foo') # => 1
160
+ # counters.fetch(:bar, 0) # => 0
161
+ # counters.fetch(:bar) { |key| 0 } # => 0
162
+ # counters.fetch(:zoo) # => KeyError: key not found: "zoo"
163
+ def fetch(key, *extras)
164
+ super(convert_key(key), *extras)
165
+ end
166
+
167
+ # Returns an array of the values at the specified indices:
168
+ #
169
+ # hash = HashWithIndifferentAccess.new
170
+ # hash[:a] = 'x'
171
+ # hash[:b] = 'y'
172
+ # hash.values_at('a', 'b') # => ["x", "y"]
173
+ def values_at(*indices)
174
+ indices.collect { |key| self[convert_key(key)] }
175
+ end
176
+
177
+ # Returns an exact copy of the hash.
178
+ def dup
179
+ self.class.new(self).tap do |new_hash|
180
+ new_hash.default = default
181
+ end
182
+ end
183
+
184
+ # This method has the same semantics of +update+, except it does not
185
+ # modify the receiver but rather returns a new hash with indifferent
186
+ # access with the result of the merge.
187
+ def merge(hash, &block)
188
+ self.dup.update(hash, &block)
189
+ end
190
+
191
+ # Like +merge+ but the other way around: Merges the receiver into the
192
+ # argument and returns a new hash with indifferent access as result:
193
+ #
194
+ # hash = HashWithIndifferentAccess.new
195
+ # hash['a'] = nil
196
+ # hash.reverse_merge(a: 0, b: 1) # => {"a"=>nil, "b"=>1}
197
+ def reverse_merge(other_hash)
198
+ super(self.class.new_from_hash_copying_default(other_hash))
199
+ end
200
+
201
+ # Same semantics as +reverse_merge+ but modifies the receiver in-place.
202
+ def reverse_merge!(other_hash)
203
+ replace(reverse_merge( other_hash ))
204
+ end
205
+
206
+ # Replaces the contents of this hash with other_hash.
207
+ #
208
+ # h = { "a" => 100, "b" => 200 }
209
+ # h.replace({ "c" => 300, "d" => 400 }) # => {"c"=>300, "d"=>400}
210
+ def replace(other_hash)
211
+ super(self.class.new_from_hash_copying_default(other_hash))
212
+ end
213
+
214
+ # Removes the specified key from the hash.
215
+ def delete(key)
216
+ super(convert_key(key))
217
+ end
218
+
219
+ def stringify_keys!; self end
220
+ def deep_stringify_keys!; self end
221
+ def stringify_keys; dup end
222
+ def deep_stringify_keys; dup end
223
+ undef :symbolize_keys!
224
+ undef :deep_symbolize_keys!
225
+ def symbolize_keys; to_hash.symbolize_keys! end
226
+ def deep_symbolize_keys; to_hash.deep_symbolize_keys! end
227
+ def to_options!; self end
228
+
229
+ def select(*args, &block)
230
+ dup.tap { |hash| hash.select!(*args, &block) }
231
+ end
232
+
233
+ def reject(*args, &block)
234
+ dup.tap { |hash| hash.reject!(*args, &block) }
235
+ end
236
+
237
+ # Convert to a regular hash with string keys.
238
+ def to_hash
239
+ _new_hash= {}
240
+ each do |key, value|
241
+ _new_hash[convert_key(key)] = convert_value(value, for: :to_hash)
242
+ end
243
+ Hash.new(default).merge!(_new_hash)
244
+ end
245
+
246
+ protected
247
+ def convert_key(key)
248
+ key.kind_of?(Symbol) ? key.to_s : key
249
+ end
250
+
251
+ def convert_value(value, options = {})
252
+ if value.is_a? Hash
253
+ if options[:for] == :to_hash
254
+ value.to_hash
255
+ else
256
+ value.nested_under_indifferent_access
257
+ end
258
+ elsif value.is_a?(Array)
259
+ unless options[:for] == :assignment
260
+ value = value.dup
261
+ end
262
+ value.map! { |e| convert_value(e, options) }
263
+ else
264
+ value
265
+ end
266
+ end
267
+ end
268
+
269
+ class Hash
270
+ # Returns a <tt>HashWithIndifferentAccess</tt> out of its receiver:
271
+ #
272
+ # { a: 1 }.with_indifferent_access['a'] # => 1
273
+ def with_indifferent_access
274
+ HashWithIndifferentAccess.new_from_hash_copying_default(self)
275
+ end
276
+
277
+ # Called when object is nested under an object that receives
278
+ # #with_indifferent_access. This method will be called on the current object
279
+ # by the enclosing object and is aliased to #with_indifferent_access by
280
+ # default. Subclasses of Hash may overwrite this method to return +self+ if
281
+ # converting to an <tt>HashWithIndifferentAccess</tt> would not be
282
+ # desirable.
283
+ #
284
+ # b = { b: 1 }
285
+ # { a: b }.with_indifferent_access['a'] # calls b.nested_under_indifferent_access
286
+ # # => {"b"=>32}
287
+ alias nested_under_indifferent_access with_indifferent_access
288
+ end
@@ -0,0 +1,140 @@
1
+ class Hash
2
+ # Returns a new hash with all keys converted using the block operation.
3
+ #
4
+ # hash = { name: 'Rob', age: '28' }
5
+ #
6
+ # hash.transform_keys{ |key| key.to_s.upcase }
7
+ # # => {"NAME"=>"Rob", "AGE"=>"28"}
8
+ def transform_keys
9
+ result = {}
10
+ each_key do |key|
11
+ result[yield(key)] = self[key]
12
+ end
13
+ result
14
+ end
15
+
16
+ # Destructively convert all keys using the block operations.
17
+ # Same as transform_keys but modifies +self+.
18
+ def transform_keys!
19
+ keys.each do |key|
20
+ self[yield(key)] = delete(key)
21
+ end
22
+ self
23
+ end
24
+
25
+ # Returns a new hash with all keys converted to strings.
26
+ #
27
+ # hash = { name: 'Rob', age: '28' }
28
+ #
29
+ # hash.stringify_keys
30
+ # # => { "name" => "Rob", "age" => "28" }
31
+ def stringify_keys
32
+ transform_keys{ |key| key.to_s }
33
+ end
34
+
35
+ # Destructively convert all keys to strings. Same as
36
+ # +stringify_keys+, but modifies +self+.
37
+ def stringify_keys!
38
+ transform_keys!{ |key| key.to_s }
39
+ end
40
+
41
+ # Returns a new hash with all keys converted to symbols, as long as
42
+ # they respond to +to_sym+.
43
+ #
44
+ # hash = { 'name' => 'Rob', 'age' => '28' }
45
+ #
46
+ # hash.symbolize_keys
47
+ # # => { name: "Rob", age: "28" }
48
+ def symbolize_keys
49
+ transform_keys{ |key| key.to_sym rescue key }
50
+ end
51
+ alias_method :to_options, :symbolize_keys
52
+
53
+ # Destructively convert all keys to symbols, as long as they respond
54
+ # to +to_sym+. Same as +symbolize_keys+, but modifies +self+.
55
+ def symbolize_keys!
56
+ transform_keys!{ |key| key.to_sym rescue key }
57
+ end
58
+ alias_method :to_options!, :symbolize_keys!
59
+
60
+ # Validate all keys in a hash match <tt>*valid_keys</tt>, raising ArgumentError
61
+ # on a mismatch. Note that keys are NOT treated indifferently, meaning if you
62
+ # use strings for keys but assert symbols as keys, this will fail.
63
+ #
64
+ # { name: 'Rob', years: '28' }.assert_valid_keys(:name, :age) # => raises "ArgumentError: Unknown key: :years. Valid keys are: :name, :age"
65
+ # { name: 'Rob', age: '28' }.assert_valid_keys('name', 'age') # => raises "ArgumentError: Unknown key: :name. Valid keys are: 'name', 'age'"
66
+ # { name: 'Rob', age: '28' }.assert_valid_keys(:name, :age) # => passes, raises nothing
67
+ def assert_valid_keys(*valid_keys)
68
+ valid_keys.flatten!
69
+ each_key do |k|
70
+ unless valid_keys.include?(k)
71
+ raise ArgumentError.new("Unknown key: #{k.inspect}. Valid keys are: #{valid_keys.map(&:inspect).join(', ')}")
72
+ end
73
+ end
74
+ end
75
+
76
+ # Returns a new hash with all keys converted by the block operation.
77
+ # This includes the keys from the root hash and from all
78
+ # nested hashes.
79
+ #
80
+ # hash = { person: { name: 'Rob', age: '28' } }
81
+ #
82
+ # hash.deep_transform_keys{ |key| key.to_s.upcase }
83
+ # # => {"PERSON"=>{"NAME"=>"Rob", "AGE"=>"28"}}
84
+ def deep_transform_keys(&block)
85
+ result = {}
86
+ each do |key, value|
87
+ result[yield(key)] = value.is_a?(Hash) ? value.deep_transform_keys(&block) : value
88
+ end
89
+ result
90
+ end
91
+
92
+ # Destructively convert all keys by using the block operation.
93
+ # This includes the keys from the root hash and from all
94
+ # nested hashes.
95
+ def deep_transform_keys!(&block)
96
+ keys.each do |key|
97
+ value = delete(key)
98
+ self[yield(key)] = value.is_a?(Hash) ? value.deep_transform_keys!(&block) : value
99
+ end
100
+ self
101
+ end
102
+
103
+ # Returns a new hash with all keys converted to strings.
104
+ # This includes the keys from the root hash and from all
105
+ # nested hashes.
106
+ #
107
+ # hash = { person: { name: 'Rob', age: '28' } }
108
+ #
109
+ # hash.deep_stringify_keys
110
+ # # => {"person"=>{"name"=>"Rob", "age"=>"28"}}
111
+ def deep_stringify_keys
112
+ deep_transform_keys{ |key| key.to_s }
113
+ end
114
+
115
+ # Destructively convert all keys to strings.
116
+ # This includes the keys from the root hash and from all
117
+ # nested hashes.
118
+ def deep_stringify_keys!
119
+ deep_transform_keys!{ |key| key.to_s }
120
+ end
121
+
122
+ # Returns a new hash with all keys converted to symbols, as long as
123
+ # they respond to +to_sym+. This includes the keys from the root hash
124
+ # and from all nested hashes.
125
+ #
126
+ # hash = { 'person' => { 'name' => 'Rob', 'age' => '28' } }
127
+ #
128
+ # hash.deep_symbolize_keys
129
+ # # => {:person=>{:name=>"Rob", :age=>"28"}}
130
+ def deep_symbolize_keys
131
+ deep_transform_keys{ |key| key.to_sym rescue key }
132
+ end
133
+
134
+ # Destructively convert all keys to symbols, as long as they respond
135
+ # to +to_sym+. This includes the keys from the root hash and from all
136
+ # nested hashes.
137
+ def deep_symbolize_keys!
138
+ deep_transform_keys!{ |key| key.to_sym rescue key }
139
+ end
140
+ end
@@ -0,0 +1,42 @@
1
+ class Hash
2
+ # Slice a hash to include only the given keys. This is useful for
3
+ # limiting an options hash to valid keys before passing to a method:
4
+ #
5
+ # def search(criteria = {})
6
+ # criteria.assert_valid_keys(:mass, :velocity, :time)
7
+ # end
8
+ #
9
+ # search(options.slice(:mass, :velocity, :time))
10
+ #
11
+ # If you have an array of keys you want to limit to, you should splat them:
12
+ #
13
+ # valid_keys = [:mass, :velocity, :time]
14
+ # search(options.slice(*valid_keys))
15
+ def slice(*keys)
16
+ keys.map! { |key| convert_key(key) } if respond_to?(:convert_key, true)
17
+ keys.each_with_object(self.class.new) { |k, hash| hash[k] = self[k] if has_key?(k) }
18
+ end
19
+
20
+ # Replaces the hash with only the given keys.
21
+ # Returns a hash containing the removed key/value pairs.
22
+ #
23
+ # { a: 1, b: 2, c: 3, d: 4 }.slice!(:a, :b)
24
+ # # => {:c=>3, :d=>4}
25
+ def slice!(*keys)
26
+ keys.map! { |key| convert_key(key) } if respond_to?(:convert_key, true)
27
+ omit = slice(*self.keys - keys)
28
+ hash = slice(*keys)
29
+ hash.default = default
30
+ hash.default_proc = default_proc if default_proc
31
+ replace(hash)
32
+ omit
33
+ end
34
+
35
+ # Removes and returns the key/value pairs matching the given keys.
36
+ #
37
+ # { a: 1, b: 2, c: 3, d: 4 }.extract!(:a, :b) # => {:a=>1, :b=>2}
38
+ # { a: 1, b: 2 }.extract!(:a, :x) # => {:a=>1}
39
+ def extract!(*keys)
40
+ keys.each_with_object(self.class.new) { |key, result| result[key] = delete(key) if has_key?(key) }
41
+ end
42
+ end
@@ -0,0 +1,8 @@
1
+ class String
2
+ def underscore
3
+ word = self.dup
4
+ word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
5
+ word.downcase!
6
+ word
7
+ end
8
+ end
data/readme.md CHANGED
@@ -5,20 +5,43 @@
5
5
  [![Build Status](https://travis-ci.org/UP-nxt/cmis-ruby.png?branch=master)](https://travis-ci.org/UP-nxt/cmis-ruby)
6
6
  [![Dependency Status](https://gemnasium.com/UP-nxt/cmis-ruby.png)](https://gemnasium.com/UP-nxt/cmis-ruby)
7
7
 
8
- **CMIS ruby** is a [CMIS](http://chemistry.apache.org/project/cmis.html) client library, using the the CMIS browser binding ([CMIS 1.1](http://docs.oasis-open.org/cmis/CMIS/v1.1/CMIS-v1.1.html)) for Ruby.
8
+ **CMIS ruby** is a [CMIS](http://chemistry.apache.org/project/cmis.html) client library, using the the _CMIS Browser Binding_ ([CMIS 1.1](http://docs.oasis-open.org/cmis/CMIS/v1.1/CMIS-v1.1.html)).
9
9
 
10
- ## Running specs
10
+ ## Example usage
11
+
12
+ #### `CMIS::Server` and `CMIS::Repository`
13
+
14
+ ```ruby
15
+ server = CMIS::Server.new(service_url: 'http://33.33.33.100:8080/browser',
16
+ username: 'foo', password: 'bar')
17
+ repository = server.repository('my_repository')
18
+ ```
19
+
20
+ #### `CMIS::document`
11
21
 
12
- Running the tests requires a separate CMIS server. The default rake task runs the specs.
22
+ ```ruby
23
+ # get by object id
24
+ document = repository.object('f3y5wbb6slhkeq3ciu3uazbpxeu')
13
25
 
14
- ## TODO
26
+ # find by unique property
27
+ document = repository.find_object('cmis:document',
28
+ 'cmis:name' => 'some_unique_name')
29
+
30
+ # set content
31
+ document.content = { stream: StringIO.new('Apple is a fruit'),
32
+ mime_type: 'text/plain',
33
+ filename: 'apple.txt' }
34
+
35
+ # create a new document
36
+ document = repository.new_document
37
+ document.name = 'new_document'
38
+ document.object_type_id = 'cmis:document'
39
+ document = document.create_in_folder(repository.root)
40
+ ```
41
+
42
+ ## Running specs
15
43
 
16
- * remove ActiveSupport dependency:
17
- * stringify_keys! -> to_options!
18
- * symbolize_keys! -> to_options!
19
- * compact!
20
- * with_indifferent_access -> ?
21
- * caching
44
+ The default rake task runs the specs. This requires a separate CMIS server. The environment variable `TEST_ENV` selects the test environment from `spec/config.yml`. The Travis build uses the private `ci` environment.
22
45
 
23
46
  ## Contributing
24
47
 
@@ -46,6 +46,17 @@ module CMIS
46
46
  end
47
47
  end
48
48
 
49
+ describe '#count_objects' do
50
+ it 'returns 1 folder (which is the root folder)' do
51
+ count = repository.count_objects('cmis:folder')
52
+ expect(count).to eq 1
53
+ end
54
+ it 'returns 0 documents' do
55
+ count = repository.count_objects('cmis:document')
56
+ expect(count).to eq 0
57
+ end
58
+ end
59
+
49
60
  describe '#new_[document|folder|relationship|item|policy|type]' do
50
61
  it 'returns the correct type' do
51
62
  expect(repository.new_document) .to be_a Document
@@ -1,3 +1,4 @@
1
+ require 'securerandom'
1
2
  require 'spec_helper'
2
3
 
3
4
  module CMIS
data/spec/config.yml CHANGED
@@ -3,6 +3,12 @@ local:
3
3
  server:
4
4
  service_url: http://33.33.33.100:8080/browser
5
5
  repository: test
6
+ ci:
7
+ server:
8
+ service_url: https://cmis-service.ci.apps.up-nxt.com/browser
9
+ username: <%= ENV['CI_USERNAME'] %>
10
+ password: <%= ENV['CI_PASSWORD'] %>
11
+ repository: travis_cmis_ruby
6
12
  nuxeo:
7
13
  server:
8
14
  service_url: http://cmis.demo.nuxeo.com/nuxeo/json/cmis
data/spec/spec_helper.rb CHANGED
@@ -1,33 +1,33 @@
1
1
  require 'cmis-ruby'
2
+ require 'yaml'
3
+ require 'erb'
2
4
 
3
5
  module SpecHelpers
4
-
5
6
  def server
6
- @server ||= CMIS::Server.new(options['server'])
7
+ @@server ||= CMIS::Server.new(options['server'])
7
8
  end
8
9
 
9
10
  def repository
10
- @repository ||= server.repository(options['repository'])
11
+ @@repository ||= server.repository(repository_id)
11
12
  end
12
13
 
13
14
  def repository_id
14
- options['repository']
15
+ @@repository_id ||= options['repository']
15
16
  end
16
17
 
17
18
  private
18
19
 
19
20
  def options
20
- file = File.join(File.dirname(File.expand_path(__FILE__)), 'config.yml')
21
- config = YAML::load_file(file)
22
- test_env = ENV['TEST_ENV'] || 'local'
21
+ path = File.join(File.dirname(File.expand_path(__FILE__)), 'config.yml')
22
+ config = YAML.load ERB.new(File.read(path)).result
23
23
 
24
+ test_env = ENV['TEST_ENV'] || 'local'
24
25
  if config.key?(test_env)
25
26
  config[test_env]
26
27
  else
27
- raise "No configuration found for #{test_env}"
28
+ raise "No configuration found for environment `#{test_env}`"
28
29
  end
29
30
  end
30
-
31
31
  end
32
32
 
33
33
  RSpec.configure do |c|
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cmis-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kenneth Geerts
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-03-20 00:00:00.000000000 Z
12
+ date: 2014-03-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: faraday
@@ -25,26 +25,6 @@ dependencies:
25
25
  - - "~>"
26
26
  - !ruby/object:Gem::Version
27
27
  version: '0.9'
28
- - !ruby/object:Gem::Dependency
29
- name: activesupport
30
- requirement: !ruby/object:Gem::Requirement
31
- requirements:
32
- - - ">="
33
- - !ruby/object:Gem::Version
34
- version: '3.2'
35
- - - "<"
36
- - !ruby/object:Gem::Version
37
- version: '5.0'
38
- type: :runtime
39
- prerelease: false
40
- version_requirements: !ruby/object:Gem::Requirement
41
- requirements:
42
- - - ">="
43
- - !ruby/object:Gem::Version
44
- version: '3.2'
45
- - - "<"
46
- - !ruby/object:Gem::Version
47
- version: '5.0'
48
28
  description: |
49
29
  CMIS browser binding client library in ruby.
50
30
  email:
@@ -82,11 +62,12 @@ files:
82
62
  - lib/cmis/server.rb
83
63
  - lib/cmis/type.rb
84
64
  - lib/cmis/version.rb
85
- - lib/core_ext.rb
86
- - lib/core_ext/array.rb
87
65
  - lib/core_ext/array/indifferent_access.rb
88
- - lib/core_ext/hash.rb
89
66
  - lib/core_ext/hash/compact.rb
67
+ - lib/core_ext/hash/indifferent_access.rb
68
+ - lib/core_ext/hash/keys.rb
69
+ - lib/core_ext/hash/slice.rb
70
+ - lib/core_ext/string/underscore.rb
90
71
  - readme.md
91
72
  - spec/cmis-ruby/document_spec.rb
92
73
  - spec/cmis-ruby/folder_spec.rb
data/lib/core_ext.rb DELETED
@@ -1,3 +0,0 @@
1
- Dir["#{File.dirname(__FILE__)}/core_ext/*.rb"].each do |path|
2
- require path
3
- end
@@ -1 +0,0 @@
1
- require 'core_ext/array/indifferent_access'
data/lib/core_ext/hash.rb DELETED
@@ -1 +0,0 @@
1
- require 'core_ext/hash/compact'