libis-tools 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +2 -0
  3. data/.gitignore +16 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +37 -0
  6. data/Gemfile +7 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +289 -0
  9. data/Rakefile +6 -0
  10. data/lib/libis-tools.rb +1 -0
  11. data/lib/libis/tools.rb +16 -0
  12. data/lib/libis/tools/assert.rb +41 -0
  13. data/lib/libis/tools/checksum.rb +84 -0
  14. data/lib/libis/tools/command.rb +40 -0
  15. data/lib/libis/tools/config.rb +160 -0
  16. data/lib/libis/tools/dc_record.rb +47 -0
  17. data/lib/libis/tools/extend/empty.rb +7 -0
  18. data/lib/libis/tools/extend/hash.rb +107 -0
  19. data/lib/libis/tools/extend/ostruct.rb +3 -0
  20. data/lib/libis/tools/extend/string.rb +85 -0
  21. data/lib/libis/tools/extend/struct.rb +29 -0
  22. data/lib/libis/tools/logger.rb +71 -0
  23. data/lib/libis/tools/mets_file.rb +575 -0
  24. data/lib/libis/tools/parameter.rb +172 -0
  25. data/lib/libis/tools/sharepoint_mapping.rb +118 -0
  26. data/lib/libis/tools/sharepoint_record.rb +260 -0
  27. data/lib/libis/tools/version.rb +5 -0
  28. data/lib/libis/tools/xml_document.rb +574 -0
  29. data/libis-tools.gemspec +39 -0
  30. data/spec/assert_spec.rb +65 -0
  31. data/spec/checksum_spec.rb +132 -0
  32. data/spec/command_spec.rb +68 -0
  33. data/spec/config_spec.rb +86 -0
  34. data/spec/data/test.data +9 -0
  35. data/spec/data/test.xml +8 -0
  36. data/spec/data/test.yml +1 -0
  37. data/spec/logger_spec.rb +107 -0
  38. data/spec/parameter_container_spec.rb +83 -0
  39. data/spec/parameter_spec.rb +139 -0
  40. data/spec/spec_helper.rb +12 -0
  41. data/spec/test.xsd +20 -0
  42. data/spec/xmldocument_spec.rb +413 -0
  43. data/test/test_helper.rb +7 -0
  44. data/test/webservices/test_ca_item_info.rb +59 -0
  45. data/test/webservices/test_ca_search.rb +35 -0
  46. metadata +244 -0
@@ -0,0 +1,84 @@
1
+ # encoding: utf-8
2
+
3
+ require 'digest'
4
+
5
+ module Libis
6
+ module Tools
7
+
8
+ # Common interface for checksum calculations.
9
+ #
10
+ # Supported checksum algortihms are MD5, RMD160 (not on JRuby), SHA-1, SHA-2 (256, 384 and 512-bit versions).
11
+ # All methods are available on the class and on the instance. The instance has to be initialized with a checksum
12
+ # algorithm and therefore the instance methods do not have to specify the checksum type.
13
+ #
14
+ class Checksum
15
+ if defined? JRUBY_VERSION
16
+ CHECKSUM_TYPES = [:MD5, :SHA1, :SHA256, :SHA384, :SHA512]
17
+ else
18
+ CHECKSUM_TYPES = [:MD5, :RMD160, :SHA1, :SHA256, :SHA384, :SHA512]
19
+ end
20
+
21
+ # Create instance for a given checksum algorithm.
22
+ #
23
+ # @param [Symbol] type checksum algorithm; one of {#CHECKSUM_TYPES}
24
+ def initialize(type)
25
+ @hasher = self.class.get_hasher(type)
26
+ end
27
+
28
+ # Calculate binary digest of a file.
29
+ #
30
+ # @param [String] file_path_or_string path of the file to calculate the digest for
31
+ def digest(file_path_or_string)
32
+ @hasher.file(file_path_or_string).digest!
33
+ end
34
+
35
+ # Calculate the hexadecimal digest of a file.
36
+ # @param (see #digest)
37
+ def hexdigest(file_path_or_string)
38
+ @hasher.file(file_path_or_string).hexdigest!
39
+ end
40
+
41
+ # Calculate the base64 digest of a file.
42
+ # @param (see #digest)
43
+ def base64digest(file_path_or_string)
44
+ @hasher.file(file_path_or_string).base64digest!
45
+ end
46
+
47
+ # Calculate the binary digest of a file.
48
+ # @param (see #digest)
49
+ # @param (see #initialize)
50
+ def self.digest(file_path_or_string, type)
51
+ new(type).digest(file_path_or_string)
52
+ end
53
+
54
+ # Calculate the hexadecimal digest of a file.
55
+ # @param (see #digest)
56
+ # @param (see #initialize)
57
+ def self.hexdigest(file_path_or_string, type)
58
+ new(type).hexdigest(file_path_or_string)
59
+ end
60
+
61
+ # Calculate the base64 digest of a file.
62
+ # @param (see #digest)
63
+ # @param (see #initialize)
64
+ def self.base64digest(file_path_or_string, type)
65
+ new(type).base64digest(file_path_or_string)
66
+ end
67
+
68
+ # Instatiate a Digest instance for access to low-level functionality
69
+ # @param (see #initialize)
70
+ def self.get_hasher(type)
71
+ raise RuntimeError, "Checksum type '#{type}' not supported." unless CHECKSUM_TYPES.include? type
72
+ Digest(type).new
73
+ end
74
+
75
+ private
76
+
77
+ def hashit(file_path_or_string)
78
+ @hasher.file(file_path_or_string)
79
+ end
80
+
81
+ end
82
+
83
+ end
84
+ end
@@ -0,0 +1,40 @@
1
+ # encoding: utf-8
2
+ require 'open3'
3
+
4
+ module Libis
5
+ module Tools
6
+
7
+ module Command
8
+
9
+ # Run an external program and return status, stdout and stderr.
10
+ #
11
+ #
12
+ # @param [String] cmd program name
13
+ # @param [Array<String>] opts optional list of command line arguments
14
+ # @return [Hash] a Hash with:
15
+ # * +:status+ : the exit status of the command
16
+ # * +:out+ : the stdout output of the command
17
+ # * +:err+ : the stderr output of the command
18
+ def self.run(cmd, *opts)
19
+ result = {}
20
+ begin
21
+ Open3.popen3(cmd, *opts) do |_, output, error, thread|
22
+ output = output.read
23
+ error = error.read
24
+ result[:out] = output.split("\n").map(&:chomp)
25
+ result[:err] = error.split("\n").map(&:chomp)
26
+ result[:status] = thread.value.exitstatus rescue nil
27
+ end
28
+
29
+ rescue Exception
30
+ # ignored
31
+
32
+ end
33
+
34
+ result
35
+
36
+ end
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,160 @@
1
+ # encoding: utf-8
2
+ require 'singleton'
3
+ require 'set'
4
+ require 'yaml'
5
+ require 'erb'
6
+ require 'logger'
7
+ require 'backports'
8
+
9
+ require 'libis/tools/extend/hash'
10
+
11
+ module Libis
12
+ module Tools
13
+
14
+ # The Config class is a convenience method for easy configuration maintenance and loading.
15
+ # It supports code defaults, loading configurations from multiple YAML files containing ERB statements.
16
+ # The Config class follows the Singleton pattern and behaves like a Hash/OpenStruct/HashWithIndifferentAccess.
17
+ # It also initializes a default Logger instance.
18
+ # The class also stores a system-wide {::Logger} instance that will be used by {::Libis::Tools::Logger}.
19
+ #
20
+ # The parameters can be accessed by getter/setter method or using the Hash syntax:
21
+ #
22
+ # require 'libis/tools/config'
23
+ # cfg = ::Libis::Tools::Config
24
+ # cfg['my_value'] = 10
25
+ # p cfg.instance.my_value # => 10
26
+ # cfg.instance.my_text = 'abc'
27
+ # p cfg[:my_text] # => 'abc'
28
+ # p cfg.logger.warn('message') # => W, [2015-03-16T12:51:01.180548 #28935] WARN -- : message
29
+ #
30
+ class Config
31
+ include Singleton
32
+
33
+ class << self
34
+
35
+ private
36
+
37
+ # For each configuration parameter, the value can be accessed via the class or the Singleton instance.
38
+ def method_missing(name, *args, &block)
39
+ instance.send(name, *args, &block)
40
+ end
41
+
42
+ end
43
+
44
+ # Load configuration parameters from a YAML file or Hash.
45
+ #
46
+ # The YAML file can contain ERB syntax values that will be evaluated at loading time. Multiple files can be
47
+ # loaded. Instead of a YAML file, a Hash can be passed. The file paths and Hashes are memorised and loaded again
48
+ # by the {#reload} methods.
49
+ # @param [String,Hash] file_or_hash
50
+ def <<(file_or_hash)
51
+ return if file_or_hash.nil?
52
+ hash = case file_or_hash
53
+ when Hash
54
+ @sources << file_or_hash
55
+ file_or_hash
56
+ when String
57
+ return unless File.exist?(file_or_hash)
58
+ @sources << File.absolute_path(file_or_hash)
59
+ data = ERB.new(open(file_or_hash).read).result
60
+ # noinspection RubyResolve
61
+ YAML.load(data).to_hash rescue {}
62
+ else
63
+ {}
64
+ end
65
+ @data.merge! hash.key_symbols_to_strings recursive: true
66
+ self
67
+ end
68
+
69
+ # Load all files and Hashes again. Will not reset the configuration parameters. Parameters set directly on the
70
+ # configuration are kept intact unless they also exist in the files or hashes in which case they will be overwritten.
71
+ def reload
72
+ sources = @sources.dup
73
+ @sources.clear
74
+ sources.each { |f| self << f }
75
+ self
76
+ end
77
+
78
+ # Load all files and Hashes again. All configuration parameters are first deleted which means that any parameters
79
+ # added directly (not via file or hash) will no longer be available. Parameters set explicitly that also exist in
80
+ # the files or hashes will be reset to the values in those files and hashes.
81
+ def reload!
82
+ @data.clear
83
+ reload
84
+ end
85
+
86
+ # Get the value of a parameter.
87
+ # @param [String, Symbol] name parameter name
88
+ # @return [Object] parameter value; nil if the parameter does not exist
89
+ def [](name)
90
+ @data.fetch(name.to_s) rescue nil
91
+ end
92
+
93
+ # Set the value of a parameter.
94
+ # If the parameter does not yet exist, it will be created.
95
+ # @param (see #[])
96
+ # @param [Object] value the new value for the parameter
97
+ # @return [Object] parameter value
98
+ def []=(name, value)
99
+ @data.store(name.to_s, value)
100
+ end
101
+
102
+ # Return the ::Logger instance.
103
+ def logger
104
+ @logger
105
+ end
106
+
107
+ # Set the ::Logger instance.
108
+ # @param [::Logger] my_logger new logger instance
109
+ def logger=(my_logger)
110
+ @logger = my_logger
111
+ end
112
+
113
+ # Set the ::Logger instance's formatter.
114
+ # If the supplied formatter is missing or nil, a default formatter will be applied. The default formatter prints
115
+ # log lines like this:
116
+ #
117
+ # <first char of severity>, [<timestamp>#<process-id>] <severity> -- <program_name> : <message>
118
+ #
119
+ # @param [Proc] formatter the formatter procedure or nil for default formatter
120
+ def set_log_formatter(formatter = nil)
121
+ logger.formatter = formatter || proc do |severity, time, progname, msg|
122
+ "%s, [%s#%d] %5s -- %s: %s\n" % [severity[0..0],
123
+ (time.strftime('%Y-%m-%dT%H:%M:%S.') << '%06d ' % time.usec),
124
+ $$, severity, progname, msg]
125
+ end
126
+ end
127
+
128
+ private
129
+
130
+ def method_missing(name, *args)
131
+ key = name.to_s
132
+ if name.to_s =~ /^(.*)(=)$/
133
+ key = $1
134
+ end
135
+ if @data.has_key?(key)
136
+ if key =~/^\w+$/ # not all key names are safe to use as method names
137
+ self.instance_eval <<-END
138
+ def #{key}
139
+ self['#{key}']
140
+ end
141
+ def #{name}=(value)
142
+ self['#{name}'] = value
143
+ end
144
+ END
145
+ end
146
+ end
147
+ ($2.nil? || $2.empty?) ? (@data.fetch(key) rescue nil) : @data.store(key, args.first)
148
+ end
149
+
150
+ def initialize
151
+ @data = Hash.new
152
+ @sources = Array.new
153
+ @logger = ::Logger.new(STDOUT)
154
+ set_log_formatter
155
+ end
156
+
157
+ end
158
+ end
159
+ end
160
+
@@ -0,0 +1,47 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative 'xml_document'
4
+
5
+ module Libis
6
+ module Tools
7
+
8
+ class DCRecord < XmlDocument
9
+
10
+ # noinspection RubyResolve
11
+ def initialize(doc = nil)
12
+ super('utf-8')
13
+ case doc
14
+ when NilClass
15
+ build do |xml|
16
+ xml[:dc].record('xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
17
+ 'xmlns:dc' => 'http://purl.org/dc/elements/1.1/',
18
+ 'xmlns:dcterms' => 'http://purl.org/dc/terms/') {
19
+ yield xml if block_given?
20
+ }
21
+ end
22
+ when ::Libis::Tools::XmlDocument
23
+ @document = doc.document.dup
24
+ when String
25
+ if File.exist?(doc)
26
+ # noinspection RubyResolve
27
+ load(doc)
28
+ else
29
+ parse(doc)
30
+ end
31
+ when Hash
32
+ self.from_hash(doc)
33
+ when IO
34
+ self.parse(doc.read)
35
+ else
36
+ raise ArgumentError, "Invalid argument: #{doc.inspect}"
37
+ end
38
+ end
39
+
40
+ def add(tag, value = nil, attributes = {})
41
+ add_node(tag, value, root, attributes)
42
+ end
43
+
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,7 @@
1
+ # encoding: utf-8
2
+
3
+ class NilClass
4
+ def empty?
5
+ true
6
+ end
7
+ end
@@ -0,0 +1,107 @@
1
+ require 'backports/rails/hash'
2
+
3
+ class Hash
4
+
5
+ def cleanup
6
+ self.delete_if { |_,v| v.nil? || (v.respond_to?(:empty?) ? v.empty? : false) }
7
+ end unless method_defined? :cleanup
8
+
9
+ def recursive_cleanup
10
+ delete_proc = Proc.new do |_, v|
11
+ v.delete_if(&delete_proc) if v.kind_of?(Hash)
12
+ v.nil? || (v.respond_to?(:empty?) ? v.empty? : false)
13
+ end
14
+ self.delete_if &delete_proc
15
+ end unless method_defined? :recursive_cleanup
16
+
17
+ def recursive_merge(other_hash)
18
+ self.merge(other_hash) do |_, old_val, new_val|
19
+ if old_val.is_a? Hash
20
+ old_val.recursive_merge new_val
21
+ else
22
+ new_val
23
+ end
24
+ end
25
+ end unless method_defined? :recursive_merge
26
+
27
+ def recursive_merge!(other_hash)
28
+ self.merge!(other_hash) do |_, old_val, new_val|
29
+ if old_val.is_a? Hash
30
+ old_val.recursive_merge new_val
31
+ else
32
+ new_val
33
+ end
34
+ end
35
+ end unless method_defined? :recursive_merge!
36
+
37
+ def key_strings_to_symbols(opts = {})
38
+ opts = {resursive: false, upcase: false, downcase: false}.merge opts
39
+
40
+ r = Hash.new
41
+ self.each_pair do |k,v|
42
+
43
+ k = k.to_s if k.kind_of? Symbol
44
+ if k.kind_of? String
45
+ k = k.downcase if opts[:downcase]
46
+ k = k.upcase if opts[:upcase]
47
+ k = k.to_sym
48
+ end
49
+
50
+ if opts[:recursive]
51
+ case v
52
+ when Hash
53
+ v = v.key_strings_to_symbols opts
54
+ when Array
55
+ # noinspection RubyResolve
56
+ v = v.collect { |a| (a.kind_of? Hash) ? a.key_strings_to_symbols(opts) : Marshal.load(Marshal.dump(a)) }
57
+ else
58
+ # noinspection RubyResolve
59
+ v = Marshal.load(Marshal.dump(v))
60
+ end
61
+ end
62
+
63
+ r[k] = v
64
+
65
+ end
66
+
67
+ r
68
+ end unless method_defined? :key_strings_to_symbols
69
+
70
+ def key_symbols_to_strings!(opts = {})
71
+ self.replace self.key_symbols_to_strings opts
72
+ end unless method_defined? :key_symbols_to_strings!
73
+
74
+ def key_symbols_to_strings(opts = {})
75
+ opts = {resursive: false, upcase: false, downcase: false}.merge opts
76
+
77
+ r = Hash.new
78
+ self.each_pair do |k,v|
79
+
80
+ k = k.to_sym if k.kind_of? String
81
+ if k.kind_of? Symbol
82
+ k = k.to_s
83
+ k = k.downcase if opts[:downcase]
84
+ k = k.upcase if opts[:upcase]
85
+ end
86
+
87
+ if opts[:recursive]
88
+ case v
89
+ when Hash
90
+ v = v.key_symbols_to_strings(opts)
91
+ when Array
92
+ # noinspection RubyResolve
93
+ v = v.collect { |a| (a.kind_of? Hash) ? a.key_symbols_to_strings(opts) : Marshal.load(Marshal.dump(a)) }
94
+ else
95
+ # noinspection RubyResolve
96
+ v = Marshal.load(Marshal.dump(v))
97
+ end
98
+ end
99
+
100
+ r[k] = v
101
+
102
+ end
103
+
104
+ r
105
+ end unless method_defined? :key_symbols_to_strings
106
+
107
+ end