cmis-ruby 0.4.0 → 0.4.1

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