file_permissions 0.1.0

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.
@@ -0,0 +1,48 @@
1
+ # encoding: UTF-8
2
+ =begin
3
+ Copyright GodObject Team <dev@godobject.net>, 2012-2016
4
+
5
+ This file is part of FilePermissions.
6
+
7
+ Permission to use, copy, modify, and/or distribute this software for any
8
+ purpose with or without fee is hereby granted, provided that the above
9
+ copyright notice and this permission notice appear in all copies.
10
+
11
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
13
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17
+ PERFORMANCE OF THIS SOFTWARE.
18
+ =end
19
+
20
+ module GodObject
21
+ module FilePermissions
22
+
23
+ # Mixin containing helper methods
24
+ #
25
+ # @private
26
+ module HelperMixin
27
+
28
+ # @return [Array<Symbol>] possible output String formats
29
+ STRING_FORMAT = Set[:long, :short].freeze
30
+
31
+ protected
32
+
33
+ # Ensures that input is Pathname
34
+ #
35
+ # @param [Pathname, String] path a path
36
+ # @param [:forbid_nil, :allow_nil] nil_handling if set to :allow_nil,
37
+ # a nil path will be passed-through. Raises an exception otherwise
38
+ # @return [Pathname] the path as Pathname object
39
+ def to_pathname(path, nil_handling = :forbid_nil)
40
+ return nil if path.nil? if nil_handling == :allow_nil
41
+
42
+ path.is_a?(Pathname) ? path : Pathname.new(path)
43
+ end
44
+
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,156 @@
1
+ # encoding: UTF-8
2
+ =begin
3
+ Copyright GodObject Team <dev@godobject.net>, 2012-2016
4
+
5
+ This file is part of FilePermissions.
6
+
7
+ Permission to use, copy, modify, and/or distribute this software for any
8
+ purpose with or without fee is hereby granted, provided that the above
9
+ copyright notice and this permission notice appear in all copies.
10
+
11
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
13
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17
+ PERFORMANCE OF THIS SOFTWARE.
18
+ =end
19
+
20
+ module GodObject
21
+ module FilePermissions
22
+
23
+ # Represents one component of the normal file mode in POSIX environments.
24
+ #
25
+ # The Mode is basically an immutable bit set consisting of the digits
26
+ # :read, :write and :execute.
27
+ class Mode
28
+ include BitSet
29
+
30
+ octal_mode = /(?<octal_mode>[0-7])/
31
+ digit_mode = /(?<digit_mode>(?:-|r|w|x){1,3})/
32
+ blank = /\p{Blank}*?/
33
+
34
+ # Regular expression for parsing a Mode from a String representation.
35
+ PATTERN = /^#{blank}(?:#{digit_mode}|#{octal_mode})#{blank}$/
36
+
37
+ # Configuration for the GodObject:::BitSet object which is used to handle
38
+ # the state internally.
39
+ BIT_SET_CONFIGURATION = Configuration.new(
40
+ read: 'r',
41
+ write: 'w',
42
+ execute: 'x'
43
+ )
44
+
45
+ extend Forwardable
46
+ include ModeMixin
47
+ include Comparable
48
+
49
+ class << self
50
+ # @!parse include ModeMixin::ClassMethods
51
+
52
+ # Creates a new Mode object by parsing a String representation.
53
+ #
54
+ # @param [String] string a String containing a mode
55
+ # @return [GodObject::FilePermissions::Mode] a new Mode object
56
+ def parse(string)
57
+ result = string.match(PATTERN)
58
+
59
+ case
60
+ when !result
61
+ raise ParserError, 'Invalid format'
62
+ when result[:octal_mode]
63
+ new(result[:octal_mode].to_i)
64
+ else
65
+ mode_components = []
66
+
67
+ result[:digit_mode].scan(/r|w|x/).each do |digit|
68
+ mode_components << :read if digit == 'r'
69
+ mode_components << :write if digit == 'w'
70
+ mode_components << :execute if digit == 'x'
71
+ end
72
+
73
+ if mode_components.uniq!
74
+ raise ParserError,
75
+ "Duplicate digit in: #{string.inspect}"
76
+ end
77
+
78
+ new(mode_components)
79
+ end
80
+ end
81
+ end
82
+
83
+ # Initializes a new Mode
84
+ #
85
+ # @return [void]
86
+ #
87
+ # @overload initialize(numeric)
88
+ # @param [Integer] numeric a numeric representation
89
+ #
90
+ # @overload initialize(enabled_digits)
91
+ # @param [Array<:read, :write, :execute>] enabled_digits a list of
92
+ # enabled digits
93
+ def initialize(*mode_components)
94
+ @bit_set = BIT_SET_CONFIGURATION.new(*mode_components)
95
+ end
96
+
97
+ # @!method enabled_digits
98
+ # @!attribute [r] enabled_digits
99
+ # @return [Set<:read, :write, :execute>] a list of all digits which are
100
+ # enabled
101
+ #
102
+ # @!method disabled_digits
103
+ # @!attribute [r] disabled_digits
104
+ # @return [Set<:read, :write, :execute>] a list of all digits which are
105
+ # disabled
106
+ #
107
+ # @!method state
108
+ # @!attribute [r] state
109
+ # @return [{(:read, :write, :execute) => true, false}] a table of all
110
+ # digits and their states
111
+ #
112
+ # @!parse alias attributes state
113
+ #
114
+ # @!method read?
115
+ # @!attribute [r] read?
116
+ # @return [true, false] the current state of the read digit
117
+ #
118
+ # @!parse alias read read?
119
+ #
120
+ # @!method write?
121
+ # @!attribute [r] write?
122
+ # @return [true, false] the current state of the write digit
123
+ #
124
+ # @!parse alias write write?
125
+ #
126
+ # @!method execute?
127
+ # @!attribute [r] execute?
128
+ # @return [true, false] the current state of the execute digit
129
+ #
130
+ # @!parse alias execute execute?
131
+ #
132
+ # @!method [](digit)
133
+ # @param [:read, :write, :execute, Integer] digit name or index of a
134
+ # digit
135
+ # @return [true, false] current state of the given digit
136
+ #
137
+ # @!method to_i
138
+ # Represents a Mode as a binary Integer.
139
+ # @return [Integer] an Integer representation
140
+ #
141
+ # @!method to_s(format)
142
+ # Represents a Mode as String.
143
+ # @param [:long, :short] format the String format
144
+ # @return [String] a String representation
145
+ #
146
+ # @!method hash
147
+ # @return (see Object#hash) identity hash for hash table usage
148
+ def_delegators :@bit_set,
149
+ :attributes, :state, :[], :enabled_digits, :disabled_digits,
150
+ :read?, :read, :write?, :write, :execute?, :execute,
151
+ :to_i, :to_s, :hash
152
+
153
+ end
154
+
155
+ end
156
+ end
@@ -0,0 +1,163 @@
1
+ # encoding: UTF-8
2
+ =begin
3
+ Copyright GodObject Team <dev@godobject.net>, 2012-2016
4
+
5
+ This file is part of FilePermissions.
6
+
7
+ Permission to use, copy, modify, and/or distribute this software for any
8
+ purpose with or without fee is hereby granted, provided that the above
9
+ copyright notice and this permission notice appear in all copies.
10
+
11
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
13
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17
+ PERFORMANCE OF THIS SOFTWARE.
18
+ =end
19
+
20
+ module GodObject
21
+ module FilePermissions
22
+
23
+ # Common functionality of both Mode and SpecialMode
24
+ module ModeMixin
25
+
26
+ # Hook for automatic inclusion of the ClassMethods mixin
27
+ # @private
28
+ def self.included(base)
29
+ base.extend ClassMethods
30
+ end
31
+
32
+ # Class mixin for Mode and SpecialMode
33
+ module ClassMethods
34
+
35
+ # Either passes through or generates a new Mode object
36
+ #
37
+ # @return [GodObject::FilePermissions::ModeMixin]
38
+ #
39
+ # @overload build(mode)
40
+ # @param [GodObject::FilePermissions::ModeMixin] mode an already
41
+ # existing Mode
42
+ #
43
+ # @overload build(string)
44
+ # @param [String] string a String representation
45
+ #
46
+ # @overload build(numeric)
47
+ # @param [Integer] numeric a numeric representation
48
+ #
49
+ # @overload build(enabled_digits)
50
+ # @param [Array<Symbol>] enabled_digits a list of enabled digits
51
+ def build(mode)
52
+ case
53
+ when mode.kind_of?(self)
54
+ mode
55
+ when mode.respond_to?(:to_str)
56
+ parse(mode)
57
+ else
58
+ new(mode)
59
+ end
60
+ end
61
+
62
+ end
63
+
64
+ # @return [GodObject::FilePermissions::ModeMixin] a new Mode with all
65
+ # digit states inverted
66
+ def invert
67
+ self.class.new(disabled_digits)
68
+ end
69
+
70
+ # @param [GodObject::FilePermissions::ModeMixin, Array<Symbol>] other
71
+ # another Mode
72
+ # @return [GodObject::FilePermissions::ModeMixin] a new Mode with the
73
+ # enabled digits of the current and other
74
+ def +(other)
75
+ other = other.enabled_digits if other.respond_to?(:enabled_digits)
76
+
77
+ self.class.new(enabled_digits + other)
78
+ end
79
+
80
+ # @param [GodObject::FilePermissions::ModeMixin, Integer] other another
81
+ # Mode
82
+ # @return [GodObject::FilePermissions::ModeMixin] a new Mode with the
83
+ # enabled digits of the current and other
84
+ def union(other)
85
+ other = other.to_i if other.respond_to?(:to_i)
86
+
87
+ self.class.new(to_i | other)
88
+ end
89
+
90
+ alias | union
91
+
92
+ # @param [GodObject::FilePermissions::ModeMixin, Array<Symbol>] other
93
+ # another Mode
94
+ # @return [GodObject::FilePermissions::ModeMixin] a new Mode with the
95
+ # enabled digits of the current without the enabled digits of other
96
+ def difference(other)
97
+ other = other.enabled_digits if other.respond_to?(:enabled_digits)
98
+
99
+ self.class.new(enabled_digits - other)
100
+ end
101
+
102
+ alias - difference
103
+
104
+ # @param [GodObject::FilePermissions::ModeMixin, Integer] other another
105
+ # Mode
106
+ # @return [GodObject::FilePermissions::ModeMixin] a new Mode with only
107
+ # those digits enabled which are enabled in both the current and other
108
+ def intersection(other)
109
+ other = other.to_i if other.respond_to?(:to_i)
110
+
111
+ self.class.new(to_i & other)
112
+ end
113
+
114
+ alias & intersection
115
+
116
+ # @param [GodObject::FilePermissions::ModeMixin, Integer] other another
117
+ # Mode
118
+ # @return [GodObject::FilePermissions::ModeMixin] a new Mode with the
119
+ # enabled digits which are enabled in only one of current and other
120
+ def symmetric_difference(other)
121
+ other = other.to_i if other.respond_to?(:to_i)
122
+
123
+ self.class.new(to_i ^ other)
124
+ end
125
+
126
+ alias ^ symmetric_difference
127
+
128
+ # Compares the Mode to another to determine its relative position.
129
+ #
130
+ # Relative position is defined by comparing the Integer representation.
131
+ #
132
+ # @note Only other Modes or Integer-likes are considered comparable.
133
+ #
134
+ # @param [Object] other other Object to be compared
135
+ # object
136
+ # @return [-1, 0, 1, nil] -1 if other is greater, 0 if other is equal and
137
+ # 1 if other is lesser than self, nil if comparison is impossible
138
+ def <=>(other)
139
+ to_i <=> other.to_i
140
+ rescue NoMethodError
141
+ nil
142
+ end
143
+
144
+ # Answers if another object is equal and of the same type family.
145
+ #
146
+ # @see GodObject::FilePermissions::ModeMixin#<=>
147
+ # @param [Object] other an object to be checked for equality
148
+ # @return [true, false] true if the object is considered equal and of the
149
+ # same type family, false otherwise
150
+ def eql?(other)
151
+ self == other && other.kind_of?(self.class)
152
+ end
153
+
154
+ # Represents a Mode as String for debugging.
155
+ #
156
+ # @return [String] a String representation for debugging
157
+ def inspect
158
+ "#<#{self.class}: #{to_s.inspect}>"
159
+ end
160
+ end
161
+
162
+ end
163
+ end
@@ -0,0 +1,149 @@
1
+ # encoding: UTF-8
2
+ =begin
3
+ Copyright GodObject Team <dev@godobject.net>, 2012-2016
4
+
5
+ This file is part of FilePermissions.
6
+
7
+ Permission to use, copy, modify, and/or distribute this software for any
8
+ purpose with or without fee is hereby granted, provided that the above
9
+ copyright notice and this permission notice appear in all copies.
10
+
11
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
13
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17
+ PERFORMANCE OF THIS SOFTWARE.
18
+ =end
19
+
20
+ module GodObject
21
+ module FilePermissions
22
+
23
+ # Represents one component of the normal file mode in POSIX environments.
24
+ #
25
+ # The SpecialMode is basically an immutable bit set consisting of the
26
+ # digits :setuid, :setgid and :sticky.
27
+ class SpecialMode
28
+ include BitSet
29
+
30
+ octal_mode = /(?<octal_mode>[0-7])/
31
+ digit_mode = /(?<digit_mode>(?:-|s){2}(?:-|t))/
32
+ blank = /\p{Blank}*?/
33
+
34
+ # Regular expression for parsing a SpecialMode from a String
35
+ # representation.
36
+ PATTERN = /^#{blank}(?:#{digit_mode}|#{octal_mode})#{blank}$/
37
+
38
+ # Configuration for the GodObject:::BitSet object which is used to handle
39
+ # the state internally.
40
+ BIT_SET_CONFIGURATION = Configuration.new(
41
+ setuid: 's',
42
+ setgid: 's',
43
+ sticky: 't'
44
+ )
45
+
46
+ extend Forwardable
47
+ include ModeMixin
48
+ include Comparable
49
+
50
+ class << self
51
+ # @!parse include ModeMixin::ClassMethods
52
+
53
+ # Creates a new SpecialMode object by parsing a String representation.
54
+ #
55
+ # @param [String] string a String containing a mode
56
+ # @return [GodObject::FilePermissions::SpecialMode] a new SpecialMode
57
+ # object
58
+ def parse(string)
59
+ result = string.match(PATTERN)
60
+
61
+ case
62
+ when !result
63
+ raise ParserError, 'Invalid format'
64
+ when result[:octal_mode]
65
+ new(result[:octal_mode].to_i)
66
+ else
67
+ mode_components = []
68
+
69
+ mode_components << :setuid if result[:digit_mode][0] == 's'
70
+ mode_components << :setgid if result[:digit_mode][1] == 's'
71
+ mode_components << :sticky if result[:digit_mode][2] == 't'
72
+
73
+ new(mode_components)
74
+ end
75
+ end
76
+ end
77
+
78
+ # Initializes a new SpecialMode
79
+ #
80
+ # @return [void]
81
+ #
82
+ # @overload initialize(numeric)
83
+ # @param [Integer] numeric a numeric representation
84
+ #
85
+ # @overload initialize(enabled_digits)
86
+ # @param [Array<:setuid, :setgid, :sticky>] enabled_digits a list of
87
+ # enabled digits
88
+ def initialize(*mode_components)
89
+ @bit_set = BIT_SET_CONFIGURATION.new(*mode_components)
90
+ end
91
+
92
+ # @!method enabled_digits
93
+ # @!attribute [r] enabled_digits
94
+ # @return [Set<:setuid, :setgid, :sticky>] a list of all digits which
95
+ # are enabled
96
+ #
97
+ # @!method disabled_digits
98
+ # @!attribute [r] disabled_digits
99
+ # @return [Set<:setuid, :setgid, :sticky>] a list of all digits which
100
+ # are disabled
101
+ #
102
+ # @!method state
103
+ # @!attribute [r] state
104
+ # @return [{(:read, :write, :execute) => true, false}] a table of all
105
+ # digits and their states
106
+ #
107
+ # @!method setuid?
108
+ # @!attribute [r] setuid?
109
+ # @return [true, false] the current state of the setuid digit
110
+ #
111
+ # @!parse alias setuid setuid?
112
+ #
113
+ # @!method setgid?
114
+ # @!attribute [r] setgid?
115
+ # @return [true, false] the current state of the setgid digit
116
+ #
117
+ # @!parse alias setgid setgid?
118
+ #
119
+ # @!method sticky?
120
+ # @attribute [r] sticky?
121
+ # @return [true, false] the current state of the sticky digit
122
+ #
123
+ # @!parse alias sticky sticky?
124
+ #
125
+ # @!method [](digit)
126
+ # @param [:setuid, :setgid, :sticky, Integer] digit name or index of a
127
+ # digit
128
+ # @return [true, false] current state of the given digit
129
+ #
130
+ # @!method to_i
131
+ # Represents a SpecialMode as a binary Integer.
132
+ # @return [Integer] an Integer representation
133
+ #
134
+ # @!method to_s(format)
135
+ # Represents a SpecialMode as String.
136
+ # @param [:long, :short] format the String format
137
+ # @return [String] a String representation
138
+ #
139
+ # @!method hash
140
+ # @return (see Object#hash) identity hash for hash table usage
141
+ def_delegators :@bit_set,
142
+ :attributes, :state, :[], :enabled_digits, :disabled_digits,
143
+ :setuid?, :setuid, :setgid?, :setgid, :sticky?, :sticky,
144
+ :to_i, :to_s, :hash
145
+
146
+ end
147
+
148
+ end
149
+ end