banditry 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c854743c128a72638b17245379ce66aeb3266f3e
4
+ data.tar.gz: 7d2b541357f00ac37354f6e38dd60aa8b9c59526
5
+ SHA512:
6
+ metadata.gz: 2bdac37736e2c1f3d00f0dc63917676dc93ff4e2cfe5b6986b4df2ab81158506f98ba0d9c906d0fbc891a2c16f37ea2b266cddb879754e1ecb52df1f85d765ed
7
+ data.tar.gz: 75d713fe996892ff04be45ceb278bba6126e79e30a7d0d9211432b8995a71480b4b4585c96fcc3a7ec63d8b48653750eb814e1b11ae5d3a15811df624d0d8337
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.6
4
+ - 2.2.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in banditmask.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 John Parker
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,134 @@
1
+ # [![Gem Version](https://badge.fury.io/rb/banditry.svg)](http://badge.fury.io/rb/banditry) [![Build Status](https://travis-ci.org/jparker/banditry.svg?branch=master)](https://travis-ci.org/jparker/banditry)
2
+
3
+ # Banditry
4
+
5
+ Banditry provides a generic wrapper for working with bitmasks.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'banditry'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install banditry
22
+
23
+ ## Usage
24
+
25
+ ### Banditry::BanditMask
26
+
27
+ Create a class which inherits from Banditry::BanditMask, and declare the
28
+ available bit names and their corresponding values.
29
+
30
+ ```ruby
31
+ class ChmodMask < Banditry::BanditMask
32
+ bit :read, 0b001
33
+ bit :write, 0b010
34
+ bit :execute, 0b100
35
+ end
36
+
37
+ ChmodMask.bits # => { :read => 1, :write => 2, :execute => 4 }
38
+ ```
39
+
40
+ Instantiate a new mask class:
41
+
42
+ ```ruby
43
+ mask = ChmodMask.new
44
+ # or
45
+ current_bitmask = 0b001 | 0b010
46
+ mask = ChmodMask.new current_bitmask
47
+ ```
48
+
49
+ Enable bits by name.
50
+
51
+ ```ruby
52
+ mask << :read << :execute
53
+ ```
54
+
55
+ Ask whether specific bits are enabled.
56
+
57
+ ```ruby
58
+ mask.include? :read # => true
59
+ mask.include? :write # => false
60
+ mask.include? :execute # => true
61
+ mask.include? :read, :write # => false
62
+ mask.include? :read, :execute # => true
63
+ ```
64
+
65
+ Retrieve a list of all currently enabled bits.
66
+
67
+ ```ruby
68
+ mask.bits # => [:read, :execute]
69
+ ```
70
+
71
+ ### Banditry
72
+
73
+ In a class with a bitmask attribute, extend Banditry and call
74
+ Banditry.bandit_mask to add accessor methods for working with the bitmask
75
+ attribute.
76
+
77
+ ```ruby
78
+ class ObjectWithBitmaskAttribute
79
+ attr_accessor :bitmask
80
+
81
+ extend Banditry
82
+ bandit_mask :bitmask, as: :bits, with: ChmodMask
83
+ end
84
+
85
+ obj = ObjectWithBitmaskAttribute.new
86
+ obj.bitmask = 0b001
87
+ ```
88
+
89
+ This gives you a reader method which returns the Banditry::BanditMask
90
+ representation of the bitmask attribute.
91
+
92
+ ```ruby
93
+ obj.bits # => #<ChmodMask:0x007f941b9518c8 @bitmask=1>
94
+ ```
95
+
96
+ It also gives you a writer method which lets you modify the bitmask. The
97
+ writer accepts Banditry::BanditMask objects or an Array of bits.
98
+
99
+ ```ruby
100
+ obj.bits |= :write
101
+ obj.bitmask # => 3
102
+ obj.bits = [:read, :execute]
103
+ obj.bitmask # => 5
104
+ ```
105
+
106
+ Finally, it gives you a query method for checking whether particular bits are
107
+ set on the bitmask.
108
+
109
+ ```ruby
110
+ obj.bits? :read # => true
111
+ obj.bits? :write # => false
112
+ obj.bits? :execute # => true
113
+ obj.bits? :read, :write # => false
114
+ obj.bits? :read, :execute # => true
115
+ ```
116
+
117
+ ## Development
118
+
119
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run
120
+ `bin/console` for an interactive prompt that will allow you to experiment.
121
+
122
+ To install this gem onto your local machine, run `bundle exec rake install`. To
123
+ release a new version, update the version number in `version.rb`, and then run
124
+ `bundle exec rake release` to create a git tag for the version, push git
125
+ commits and tags, and push the `.gem` file to
126
+ [rubygems.org](https://rubygems.org).
127
+
128
+ ## Contributing
129
+
130
+ 1. Fork it ( https://github.com/jparker/banditry/fork )
131
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
132
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
133
+ 4. Push to the branch (`git push origin my-new-feature`)
134
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << 'test'
6
+ t.pattern = 'test/**/test_*.rb'
7
+ end
8
+
9
+ task default: :test
data/banditry.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'banditry/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "banditry"
8
+ spec.version = Banditry::VERSION
9
+ spec.authors = ["John Parker"]
10
+ spec.email = ["jparker@urgetopunt.com"]
11
+
12
+ spec.summary = %q{Generic implementation of a bitmask.}
13
+ spec.description = %q{Banditry provides a generic wrapper class to manage a bitmask attribute. Formerly known as "banditmask".}
14
+ spec.homepage = "https://github.com/jparker/banditry"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.required_ruby_version = '>= 2.1'
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.9"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency 'minitest', '~> 5.7'
27
+
28
+ spec.add_development_dependency 'pry'
29
+ end
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "banditry"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ require "pry"
11
+ Pry.start
12
+
13
+ # require "irb"
14
+ # IRB.start
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,161 @@
1
+ module Banditry
2
+ class BanditMask
3
+ attr_reader :bitmask
4
+
5
+ def initialize(bitmask = nil) # :nodoc:
6
+ @bitmask = bitmask || 0b0
7
+ end
8
+
9
+ ##
10
+ # Returns a Hash mapping all defined names to their respective bits.
11
+ #
12
+ # class MyMask < Banditry::BanditMask
13
+ # bit :read, 0b01
14
+ # bit :write, 0b10
15
+ # end
16
+ #
17
+ # MyMask.bits # => { :read => 1, :write => 2 }
18
+ def self.bits
19
+ @bits ||= {}
20
+ end
21
+
22
+ ##
23
+ # Maps +name+ to +value+ in the global list of defined bits.
24
+ #
25
+ # class MyMask < Banditry::BanditMask
26
+ # bit :read, 0b001
27
+ # bit :write, 0b010
28
+ # bit :execute, 0b100
29
+ # end
30
+ def self.bit(name, value)
31
+ bits.update name => value
32
+ end
33
+
34
+ ##
35
+ # Returns integer value of current bitmask.
36
+ def to_i
37
+ bitmask
38
+ end
39
+
40
+ ##
41
+ # Returns an array of names of the currently enabled bits.
42
+ #
43
+ # class MyMask < Banditry::BanditMask
44
+ # bit :read, 0b01
45
+ # bit :write, 0b10
46
+ # end
47
+ #
48
+ # mask = MyMask.new 0b01
49
+ # mask.bits # => [:read]
50
+ def bits
51
+ self.class.bits.select { |bit, _| include? bit }.keys
52
+ end
53
+ alias_method :to_a, :bits
54
+
55
+ ##
56
+ # Enables the bit named +bit+. Returns +self+, so calls to #<< can be
57
+ # chained. (Think Array#<<.) Raises +ArgumentError+ if +bit+ does not
58
+ # correspond to a bit that was previously defined with
59
+ # Banditry::BanditMask.bit.
60
+ #
61
+ # class MyMask < Banditry::BanditMask
62
+ # bit :read, 0b01
63
+ # bit :write, 0b10
64
+ # end
65
+ #
66
+ # mask = MyMask.new # => #<MyMask:0x007f9ebd44ae40 @bitmask=0>
67
+ # mask << :read << :write # => #<MyMask:0x007f9ebd44ae40 @bitmask=3>
68
+ def <<(bit)
69
+ @bitmask |= bit_value(bit)
70
+ self
71
+ end
72
+
73
+ ##
74
+ # Returns a new instance with the current bitmask plus +bit+. Raises
75
+ # +ArgumentError+ if +bit+ does not correspond to a bit that was previously
76
+ # defined by Banditry::BanditMask.bit.
77
+ #
78
+ # class MyMask < Banditry::BanditMask
79
+ # bit :read, 0b01
80
+ # bit :write, 0b10
81
+ # end
82
+ #
83
+ # mask = MyMask.new 0b01
84
+ # mask | :write # => #<MyMask:0x007f9e0bcf5d90 @bitmask=3>
85
+ def |(bit)
86
+ self.class.new bitmask | bit_value(bit)
87
+ end
88
+
89
+ ##
90
+ # Returns +true+ if +other+ is an instance of the same class as +self+ and
91
+ # they have the same bitmask.
92
+ #
93
+ # class MyMask < Banditry::BanditMask
94
+ # bit :read, 0b01
95
+ # bit :write, 0b10
96
+ # end
97
+ #
98
+ # class MyOtherMask < Banditry::BanditMask
99
+ # bit :chocolate, 0b01
100
+ # bit :vanilla, 0b10
101
+ # end
102
+ #
103
+ # a = MyMask.new 0b1
104
+ # b = MyMask.new 0b1
105
+ # c = MyMask.new 0b0
106
+ # d = MyOtherMask.new 0b1
107
+ #
108
+ # a == b # => true
109
+ # a == c # => false
110
+ # a == d # => false
111
+ def ==(other)
112
+ other.class == self.class && other.bitmask == bitmask
113
+ end
114
+
115
+ alias_method :eql?, :==
116
+
117
+ ##
118
+ # Returns an object hash. Two Banditry::BanditMask objects have identical
119
+ # hashes if they have identical bitmasks and are instances of the same
120
+ # class.
121
+ def hash
122
+ [bitmask, self.class].hash
123
+ end
124
+
125
+ ##
126
+ # Returns true if every bit in +bits+ is enabled and false otherwise.
127
+ # Raises +ArgumentError+ if +bits+ is empty or if any element in +bits+
128
+ # does not correspond to a bit that was previously defined with
129
+ # Banditry::BanditMask.bit.
130
+ #
131
+ # class MyMask < Banditry::BanditMask
132
+ # bit :read, 0b001
133
+ # bit :write, 0b010
134
+ # bit :execute, 0b100
135
+ # end
136
+ #
137
+ # mask = MyMask.new 0b101
138
+ #
139
+ # mask.include? :read # => true
140
+ # mask.include? :write # => false
141
+ # mask.include? :execute # => true
142
+ #
143
+ # mask.include? :read, :write # => false
144
+ # mask.include? :read, :execute # => true
145
+ def include?(*bits)
146
+ raise ArgumentError, 'wrong number of arguments (0 for 1+)' if bits.empty?
147
+ bits.all? { |bit| bitmask & bit_value(bit) != 0 }
148
+ end
149
+
150
+ private
151
+
152
+ ##
153
+ # Returns the integer value for the bit named +bit+. Raises +ArgumentError+
154
+ # if +bit+ has not been previously defined with Banditry::BanditMask.bit.
155
+ def bit_value(bit)
156
+ self.class.bits.fetch(bit) do
157
+ raise ArgumentError, "undefined bit: #{bit.inspect}"
158
+ end
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,3 @@
1
+ module Banditry
2
+ VERSION = '0.4.0'
3
+ end
data/lib/banditry.rb ADDED
@@ -0,0 +1,94 @@
1
+ require 'banditry/version'
2
+ require 'banditry/bandit_mask'
3
+
4
+ module Banditry
5
+ class BanditryError < StandardError
6
+ end
7
+
8
+ class MethodCollisionError < BanditryError
9
+ end
10
+
11
+ ##
12
+ # Creates wrapper methods for reading, writing, and querying the bitmask
13
+ # stored in +attribute+ using the class +with+. +with+ defaults to
14
+ # Banditry::BanditMask, but you can (and probably should) define your own
15
+ # class inheriting from+Banditry::BanditMask to fill this role. The name of
16
+ # the accessor methods will be derived from +as+, e.g., if +as+ is +:foo+,
17
+ # the methods will be named +:foo+, +:foo=+, and +:foo?+.
18
+ #
19
+ # The reader method will return a Banditry::BanditMask representation of
20
+ # +attribute+.
21
+ #
22
+ # The writer method overwrites the current bitmask if with an Array of bits,
23
+ # or it updates the current bitmask if sent an individual bit, e.g., using
24
+ # +#|+.
25
+ #
26
+ # In addition to the accessor methods, a query method that delegates to
27
+ # Banditry::BanditMask#include? will be added.
28
+ #
29
+ # class FileMask < Banditry::BanditMask
30
+ # bit :r, 0b001
31
+ # bit :w, 0b010
32
+ # bit :x, 0b100
33
+ # end
34
+ #
35
+ # class FileObject
36
+ # attr_accessor :mode_mask
37
+ #
38
+ # extend Banditry
39
+ # bandit_mask :mode_mask, as: :mode, with: FileMask
40
+ # end
41
+ #
42
+ # file = FileObject.new
43
+ # file.mode_mask # => nil
44
+ # file.mode |= :r
45
+ # file.mode_mask # => 1
46
+ # file.mode |= :w
47
+ # file.mode_mask # => 3
48
+ # file.mode = [:r, :x]
49
+ # file.mode_mask # => 5
50
+ def bandit_mask(attribute, as:, with: BanditMask)
51
+ class_eval do
52
+ generate_reader attribute, as, with
53
+ generate_writer attribute, as, with
54
+ generate_query attribute, as, with
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ def generate_reader(attr, virt, cls)
61
+ respond_to? virt and
62
+ raise MethodCollisionError, "method `#{virt}` already exists"
63
+
64
+ define_method virt do
65
+ instance_variable_get(:"@#{virt}") ||
66
+ instance_variable_set(:"@#{virt}", cls.new(send(attr)))
67
+ end
68
+ end
69
+
70
+ def generate_writer(attr, virt, cls)
71
+ respond_to? :"#{virt}=" and
72
+ raise MethodCollisionError, "method `#{virt}=` already exists"
73
+
74
+ define_method :"#{virt}=" do |bits|
75
+ mask = case bits
76
+ when BanditMask
77
+ bits
78
+ else
79
+ bits.inject(cls.new) { |bm, bit| bm << bit }
80
+ end
81
+ send :"#{attr}=", Integer(mask)
82
+ instance_variable_set :"@#{virt}", mask
83
+ end
84
+ end
85
+
86
+ def generate_query(attr, virt, cls)
87
+ respond_to? :"#{virt}?" and
88
+ raise MethodCollisionError, "method `#{virt}?` already exists"
89
+
90
+ define_method :"#{virt}?" do |*bits|
91
+ cls.new(send(attr)).include? *bits
92
+ end
93
+ end
94
+ end
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: banditry
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.0
5
+ platform: ruby
6
+ authors:
7
+ - John Parker
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-07-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.9'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.9'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.7'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.7'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Banditry provides a generic wrapper class to manage a bitmask attribute.
70
+ Formerly known as "banditmask".
71
+ email:
72
+ - jparker@urgetopunt.com
73
+ executables: []
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".gitignore"
78
+ - ".travis.yml"
79
+ - Gemfile
80
+ - LICENSE.txt
81
+ - README.md
82
+ - Rakefile
83
+ - banditry.gemspec
84
+ - bin/console
85
+ - bin/setup
86
+ - lib/banditry.rb
87
+ - lib/banditry/bandit_mask.rb
88
+ - lib/banditry/version.rb
89
+ homepage: https://github.com/jparker/banditry
90
+ licenses:
91
+ - MIT
92
+ metadata: {}
93
+ post_install_message:
94
+ rdoc_options: []
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: '2.1'
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ requirements: []
108
+ rubyforge_project:
109
+ rubygems_version: 2.4.8
110
+ signing_key:
111
+ specification_version: 4
112
+ summary: Generic implementation of a bitmask.
113
+ test_files: []