redstruct 0.1.7 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +15 -11
  3. data/Rakefile +5 -5
  4. data/lib/redstruct/all.rb +14 -0
  5. data/lib/redstruct/configuration.rb +9 -6
  6. data/lib/redstruct/connection_proxy.rb +123 -0
  7. data/lib/redstruct/counter.rb +96 -0
  8. data/lib/redstruct/error.rb +2 -0
  9. data/lib/redstruct/factory/object.rb +31 -0
  10. data/lib/redstruct/factory.rb +94 -55
  11. data/lib/redstruct/hash.rb +123 -0
  12. data/lib/redstruct/list.rb +315 -0
  13. data/lib/redstruct/lock.rb +183 -0
  14. data/lib/redstruct/script.rb +104 -0
  15. data/lib/redstruct/set.rb +155 -0
  16. data/lib/redstruct/sorted_set/slice.rb +124 -0
  17. data/lib/redstruct/sorted_set.rb +153 -0
  18. data/lib/redstruct/string.rb +66 -0
  19. data/lib/redstruct/struct.rb +87 -0
  20. data/lib/redstruct/utils/coercion.rb +14 -8
  21. data/lib/redstruct/utils/inspectable.rb +8 -4
  22. data/lib/redstruct/utils/iterable.rb +52 -0
  23. data/lib/redstruct/utils/scriptable.rb +32 -6
  24. data/lib/redstruct/version.rb +4 -1
  25. data/lib/redstruct.rb +17 -51
  26. data/lib/yard/defscript_handler.rb +5 -3
  27. data/test/redstruct/configuration_test.rb +13 -0
  28. data/test/redstruct/connection_proxy_test.rb +85 -0
  29. data/test/redstruct/counter_test.rb +108 -0
  30. data/test/redstruct/factory/object_test.rb +21 -0
  31. data/test/redstruct/factory_test.rb +136 -0
  32. data/test/redstruct/hash_test.rb +138 -0
  33. data/test/redstruct/list_test.rb +244 -0
  34. data/test/redstruct/lock_test.rb +108 -0
  35. data/test/redstruct/script_test.rb +53 -0
  36. data/test/redstruct/set_test.rb +219 -0
  37. data/test/redstruct/sorted_set/slice_test.rb +10 -0
  38. data/test/redstruct/sorted_set_test.rb +219 -0
  39. data/test/redstruct/string_test.rb +8 -0
  40. data/test/redstruct/struct_test.rb +61 -0
  41. data/test/redstruct/utils/coercion_test.rb +33 -0
  42. data/test/redstruct/utils/inspectable_test.rb +31 -0
  43. data/test/redstruct/utils/iterable_test.rb +94 -0
  44. data/test/redstruct/utils/scriptable_test.rb +67 -0
  45. data/test/redstruct_test.rb +14 -0
  46. data/test/test_helper.rb +77 -1
  47. metadata +58 -26
  48. data/lib/redstruct/connection.rb +0 -47
  49. data/lib/redstruct/factory/creation.rb +0 -95
  50. data/lib/redstruct/factory/deserialization.rb +0 -7
  51. data/lib/redstruct/hls/lock.rb +0 -175
  52. data/lib/redstruct/hls/queue.rb +0 -29
  53. data/lib/redstruct/hls.rb +0 -2
  54. data/lib/redstruct/types/base.rb +0 -36
  55. data/lib/redstruct/types/counter.rb +0 -65
  56. data/lib/redstruct/types/hash.rb +0 -72
  57. data/lib/redstruct/types/list.rb +0 -76
  58. data/lib/redstruct/types/script.rb +0 -56
  59. data/lib/redstruct/types/set.rb +0 -96
  60. data/lib/redstruct/types/sorted_set.rb +0 -129
  61. data/lib/redstruct/types/string.rb +0 -64
  62. data/lib/redstruct/types/struct.rb +0 -58
  63. data/lib/releaser/logger.rb +0 -15
  64. data/lib/releaser/repository.rb +0 -32
  65. data/lib/tasks/release.rake +0 -49
  66. data/test/redstruct/restruct_test.rb +0 -4
@@ -1,36 +0,0 @@
1
- module Redstruct
2
- module Types
3
- # Base class for all objects a factory can produce
4
- class Base
5
- include Redstruct::Utils::Inspectable
6
- extend Forwardable
7
-
8
- def_delegators :@factory, :connection, :connection
9
-
10
- # @return [String] The key used to identify the struct on redis
11
- attr_reader :key
12
-
13
- def initialize(key:, factory:)
14
- @factory = factory
15
- @key = key
16
- end
17
-
18
- def to_h
19
- return { key: @key }
20
- end
21
-
22
- def create
23
- return unless block_given?
24
- subfactory = @factory.factory(@key)
25
- yield(subfactory)
26
- end
27
- protected :create
28
-
29
- # :nocov:
30
- def inspectable_attributes
31
- { key: @key, factory: @factory }
32
- end
33
- # :nocov:
34
- end
35
- end
36
- end
@@ -1,65 +0,0 @@
1
- module Redstruct
2
- module Types
3
- class Counter < Redstruct::Types::String
4
- include Redstruct::Utils::Scriptable
5
-
6
- def initialize(increment: 1, max: nil, **options)
7
- super(**options)
8
- @increment = increment
9
- @max = max
10
- end
11
-
12
- def get
13
- super.to_i
14
- end
15
-
16
- def set(value, **options)
17
- super(value.to_i, **options)
18
- end
19
-
20
- def increment(by: nil, max: nil)
21
- by ||= @increment
22
- max ||= @max
23
-
24
- value = if max.nil?
25
- self.connection.incrby(@key, by.to_i).to_i
26
- else
27
- ring_increment_script(keys: @key, argv: [by.to_i, max.to_i]).to_i
28
- end
29
-
30
- return value
31
- end
32
-
33
- def decrement(by: nil, max: nil)
34
- by ||= @increment
35
- by = -by.to_i
36
- return increment(by: by, max: max)
37
- end
38
-
39
- def getset(value)
40
- return super(value.to_i).to_i
41
- end
42
-
43
- # @!group Lua Scripts
44
-
45
- defscript :ring_increment_script, <<~LUA
46
- local by = tonumber(ARGV[1])
47
- local max = tonumber(ARGV[2])
48
- local current = redis.call('get', KEYS[1])
49
- local value = current and tonumber(current) or 0
50
-
51
- value = (value + by) % max
52
- redis.call('set', KEYS[1], value)
53
-
54
- return value
55
- LUA
56
-
57
- # @!endgroup
58
-
59
- # Helper method for easy inspection
60
- def inspectable_attributes
61
- super.merge(max: @max, increment: @increment)
62
- end
63
- end
64
- end
65
- end
@@ -1,72 +0,0 @@
1
- module Redstruct
2
- module Types
3
- class Hash < Redstruct::Types::Struct
4
- include Redstruct::Utils::Coercion
5
-
6
- def [](key)
7
- return self.connection.hget(@key, key)
8
- end
9
-
10
- def []=(key, value)
11
- self.connection.hset(@key, key, value)
12
- end
13
-
14
- def set(key, value, overwrite: true)
15
- if overwrite
16
- self[key] = value
17
- else
18
- self.connection.hsetnx(@key, key, value)
19
- end
20
- end
21
-
22
- def get(*keys)
23
- return self[keys.first] if keys.size == 1
24
- return self.connection.mapped_hmget(@key, *keys)
25
- end
26
-
27
- def update(hash)
28
- self.connection.mapped_hmset(@key, hash)
29
- end
30
-
31
- def remove(*keys)
32
- return self.connection.hdel(@key, keys)
33
- end
34
-
35
- def key?(key)
36
- return coerce_bool(self.connection.hexists(@key, key))
37
- end
38
-
39
- def incr(key, increment: 1)
40
- if increment.is_a?(Float)
41
- self.connection.hincrbyfloat(@key, key, increment.to_f)
42
- else
43
- self.connection.hincrby(@key, key, increment)
44
- end
45
- end
46
-
47
- def decr(key, increment: 1)
48
- return incr(key, -increment)
49
- end
50
-
51
- def to_h
52
- return self.connection.hgetall(@key)
53
- end
54
-
55
- def keys
56
- return self.connection.hkeys(@key)
57
- end
58
-
59
- def values
60
- return self.connection.hvals(@key)
61
- end
62
-
63
- def size
64
- return self.connection.hlen(@key)
65
- end
66
-
67
- def each(options = {}, &block)
68
- return self.connection.hscan_each(@key, options, &block)
69
- end
70
- end
71
- end
72
- end
@@ -1,76 +0,0 @@
1
- module Redstruct
2
- module Types
3
- class List < Redstruct::Types::Struct
4
- include Redstruct::Utils::Scriptable
5
-
6
- def clear
7
- delete
8
- end
9
-
10
- def empty?
11
- return !exists?
12
- end
13
-
14
- def [](index)
15
- return self.connection.lindex(@key, index.to_i)
16
- end
17
-
18
- def []=(index, value)
19
- return self.connection.lset(@key, index.to_i, value)
20
- end
21
-
22
- def append(*elements, max: 0)
23
- max = max.to_i
24
- return self.connection.rpush(@key, elements) if max <= 0
25
- return push_and_trim_script(keys: @key, argv: [max - 1, 0] + elements)
26
- end
27
-
28
- def prepend(*elements, max: nil)
29
- max = max.to_i
30
- return self.connection.lpush(@key, elements) if max <= 0
31
- return push_and_trim_script(keys: @key, argv: [max - 1, 1] + elements)
32
- end
33
-
34
- def pop(timeout: nil)
35
- return timeout.nil? ? self.connection.lpop(@key) : self.connection.blpop(@key, timeout: timeout)&.last
36
- end
37
-
38
- def remove(value, count: 1)
39
- count = [1, count.to_i].max
40
- self.connection.lrem(@key, count, value)
41
- end
42
-
43
- def size
44
- return self.connection.llen(@key)
45
- end
46
-
47
- def slice(start = 0, length = -1)
48
- return self.connection.lrange(@key, start.to_i, length.to_i)
49
- end
50
-
51
- def to_a
52
- return slice(0, -1)
53
- end
54
-
55
- # Appends or prepends (argv[1]) a number of items (argv[2]) to a list (keys[1]),
56
- # then trims it out to size (argv[3])
57
- # @param [Array<(::String)>] keys First key should be the key to the list to prepend to and resize
58
- # @param [Array<(Fixnum, Fixnum, Array<::String>)>] argv The maximum size of the list; if 1, will lpush, otherwise rpush; the list of items to prepend
59
- # @return [Fixnum] The length of the list after the operation
60
- defscript :push_and_trim_script, <<~LUA
61
- local max = tonumber(table.remove(ARGV, 1))
62
- local prepend = tonumber(table.remove(ARGV, 1)) == 1
63
- local push = prepend and 'lpush' or 'rpush'
64
-
65
- local size = redis.call(push, KEYS[1], unpack(ARGV))
66
- if size > max then
67
- redis.call('ltrim', KEYS[1], 0, max)
68
- size = max + 1
69
- end
70
-
71
- return size
72
- LUA
73
- protected :push_and_trim_script
74
- end
75
- end
76
- end
@@ -1,56 +0,0 @@
1
- require 'digest'
2
-
3
- module Redstruct
4
- module Types
5
- # It is recommended you flush your script cache on the redis server every once in a while
6
- class Script < Redstruct::Types::Base
7
- ERROR_MESSAGE_PREFIX = 'NOSCRIPT'.freeze
8
-
9
- # @return [::String] The Lua script to evaluate
10
- attr_reader :script
11
-
12
- def initialize(script:, **options)
13
- script = script&.strip
14
- raise(Redstruct::Error, 'No source script given') if script.empty?
15
-
16
- super(**options)
17
- self.script = script
18
- end
19
-
20
- def script=(script)
21
- @sha1 = nil
22
- @script = script.dup.freeze
23
- end
24
-
25
- def sha1
26
- return @sha1 ||= begin
27
- Digest::SHA1.hexdigest(@script)
28
- end
29
- end
30
-
31
- def exists?
32
- return self.connection.script(:exists, self.sha1)
33
- end
34
-
35
- def load
36
- @sha1 = self.connection.script(:load, @script)
37
- return @sha1
38
- end
39
-
40
- def eval(keys:, argv:)
41
- keys = [keys] unless keys.is_a?(Array)
42
- argv = [argv] unless argv.is_a?(Array)
43
- self.connection.evalsha(self.sha1, keys, argv)
44
- rescue Redis::CommandError => err
45
- raise unless err.message.start_with?(ERROR_MESSAGE_PREFIX)
46
- self.connection.eval(@script, keys, argv)
47
- end
48
-
49
- # :nocov:
50
- def inspectable_attributes
51
- return super.merge(sha1: self.sha1, script: @script.slice(0, 20))
52
- end
53
- # :nocov:
54
- end
55
- end
56
- end
@@ -1,96 +0,0 @@
1
- # frozen_string_literal: true
2
- module Redstruct
3
- module Types
4
- # Note: keep in mind Redis converts everything to a string on the DB side
5
- class Set < Redstruct::Types::Struct
6
- def clear
7
- delete
8
- end
9
-
10
- def random(count: 1)
11
- list = self.connection.srandmember(@key, count)
12
- return count == 1 ? list[0] : Set.new(list)
13
- end
14
-
15
- def empty?
16
- return !exists?
17
- end
18
-
19
- def contain?(member)
20
- return self.connection.sismember(@key, member)
21
- end
22
- alias_method :include?, :contain?
23
-
24
- def to_a
25
- return self.connection.smembers(@key)
26
- end
27
-
28
- def add(*members)
29
- return self.connection.sadd(@key, members)
30
- end
31
- alias_method :<<, :add
32
-
33
- def size
34
- return self.connection.scard(@key).to_i
35
- end
36
-
37
- def -(other)
38
- return ::Set.new(self.connection.sdiff(@key, other.key))
39
- end
40
-
41
- def +(other)
42
- return ::Set.new(self.connection.sunion(@key, other.key))
43
- end
44
-
45
- def |(other)
46
- return ::Set.new(self.connection.sinter(@key, other.key))
47
- end
48
-
49
- def difference(other, dest: nil)
50
- destination = coerce_destination(dest)
51
- return self - other if destination.nil?
52
-
53
- self.connection.sdiffstore(destination.key, @key, other.key)
54
- return destination
55
- end
56
-
57
- def intersection(other, dest: nil)
58
- destination = coerce_destination(dest)
59
- return self - other if destination.nil?
60
-
61
- self.connection.sinterstore(destination.key, @key, other.key)
62
- return destination
63
- end
64
-
65
- def union(other, dest: nil)
66
- destination = coerce_destination(dest)
67
- return self - other if destination.nil?
68
-
69
- self.connection.sunionstore(destination.key, @key, other.key)
70
- return destination
71
- end
72
-
73
- def pop
74
- return self.connection.spop(@key)
75
- end
76
-
77
- def remove(*members)
78
- return self.connection.srem(@key, *members)
79
- end
80
-
81
- def each(options = {}, &block)
82
- return self.connection.sscan_each(@key, options, &block)
83
- end
84
-
85
- def coerce_destination(dest)
86
- return case dest
87
- when ::String
88
- @factory.set(dest)
89
- when self.class
90
- dest
91
- end
92
- end
93
- private :coerce_destination
94
- end
95
- end
96
- end
@@ -1,129 +0,0 @@
1
- # frozen_string_literal: true
2
- module Redstruct
3
- module Types
4
- class SortedSet < Redstruct::Types::Struct
5
- # @param [Array<Array<#to_f, #to_s>>] pairs a list of pairs, where the first element is the score, and second the value
6
- # @return [Integer] returns the amount of pairs inserted
7
- def add(*pairs)
8
- return self.connection.zadd(@key, pairs)
9
- end
10
-
11
- # @param [Array<#to_s>] values list of member values to remove from the set
12
- # @return [Integer] the amount of elements removed
13
- def remove(*values)
14
- return self.connection.zrem(@key, values)
15
- end
16
-
17
- # Removes all items from the set. Does this by simply deleting the key
18
- # @see Redstruct::Struct#delete
19
- def clear
20
- delete
21
- end
22
-
23
- # Returns the cardinality of the set
24
- # @return [Integer] how many items are in the set
25
- def size
26
- return self.connection.zcard(@key)
27
- end
28
-
29
- # Returns the number of items between lower and upper bounds.
30
- # By default lower and upper are inclusive. If you want to make them exclusive, prepend the value with "("
31
- # @param [#to_s, #to_f] lower lower bound for the count range
32
- # @param [#to_s, #to_f] upper upper bound for the count range
33
- # @return [Integer] the number of items in the given range
34
- def count(lower: nil, upper: nil)
35
- return slice(lower: lower, upper: upper).size
36
- end
37
-
38
- # Returns a slice or partial selection of the set.
39
- # @param [#to_s, #to_f] lower lower bound for the slice operation; it should be a simple float
40
- # @param [#to_s, #to_f] upper upper bound for the slice operation; it should be a simple float
41
- # @return [Redstruct::Types::SortedSet::Slice] sorted slice by given bounds, as list of pairs: (score, value)
42
- def slice(lower: nil, upper: nil)
43
- return self.class::Slice.new(self, lower: lower, upper: upper)
44
- end
45
-
46
- # Checks if the set contains any items.
47
- # @return [Boolean] true if the key exists (meaning it contains at least 1 item), false otherwise
48
- def empty?
49
- return !self.connection.exists?
50
- end
51
-
52
- # @param [#to_s] item the item to check for
53
- # @return [Boolean] true if the item is in the set, false otherwise
54
- def contain?(item)
55
- return !index(item).nil?
56
- end
57
- alias include? contain?
58
-
59
- # Returns the index of the item in the set, sorted ascending by score
60
- # @param [#to_s] item the item to check for
61
- # @return [Integer, nil] the index of the item, or nil if not found
62
- # @see Redis#zrank
63
- def index(item)
64
- return self.connection.zrank(@key, item)
65
- end
66
-
67
- # Returns the index of the item in the set, sorted descending by score
68
- # @param [#to_s] item the item to check for
69
- # @return [Integer, nil] the index of the item, or nil if not found
70
- # @see Redis#zrevrank
71
- def rindex(item)
72
- return self.connection.zrevrank(@key, item)
73
- end
74
-
75
- # Returns an array representation of the set, sorted by score ascending
76
- # NOTE: It pulls the whole set into memory, so use each if that's a concern
77
- # @return [Array<Redstruct::Utils::ScoredValue>] all the items in the set, sorted by score ascending
78
- # @see Redis#zrange
79
- def to_a
80
- return slice.to_a
81
- end
82
-
83
- # Utility class to allow operations on portions of the set only
84
- class Slice
85
- include Redstruct::Utils::Inspectable
86
-
87
- # @param [String, Float] lower lower bound for the slice operation
88
- # @param [String, Float] upper upper bound for the slice operation
89
- def initialize(set, lower: nil, upper: nil)
90
- @set = set
91
- @lower = parse_bound(lower || '-inf')
92
- @upper = parse_bound(upper || '+inf')
93
- end
94
-
95
- # @return [Array<String>] returns an array of values for the given scores
96
- def to_a
97
- @set.connection.zrangebyscore(@set.key, @lower, @upper)
98
- end
99
-
100
- # @return [Integer] the number of elements removed
101
- def remove
102
- @set.connection.zremrangebyscore(@set.key, @lower, @upper)
103
- end
104
-
105
- # @return [Integer] number of elements in the slice
106
- def size
107
- @set.connection.zcount(@set.key, @lower, @upper)
108
- end
109
-
110
- def inspectable_attributes
111
- { lower: @lower, upper: @upper, set: @set }
112
- end
113
-
114
- private
115
-
116
- def parse_bound(bound)
117
- case bound
118
- when -Float::INFINITY
119
- '-inf'
120
- when Float::INFINITY
121
- '+inf'
122
- else
123
- bound
124
- end
125
- end
126
- end
127
- end
128
- end
129
- end
@@ -1,64 +0,0 @@
1
- module Redstruct
2
- module Types
3
- class String < Redstruct::Types::Struct
4
- include Redstruct::Utils::Scriptable, Redstruct::Utils::Coercion
5
-
6
- # @return [::String] The string value stored in the database
7
- def get
8
- return self.connection.get(@key)
9
- end
10
-
11
- # @param [Object] value The object to store; note, it will be stored using a string representation
12
- # @param [Integer] expiry The expiry time in seconds; if nil, will never expire
13
- # @param [Boolean] nx Not Exists: if true, will not set the key if it already existed
14
- # @param [Boolean] xx Already Exists: if true, will set the key only if it already existed
15
- # @return [Boolean] True if set, false otherwise
16
- def set(value, expiry: nil, nx: nil, xx: nil)
17
- options = {}
18
- options[:ex] = expiry.to_i unless expiry.nil?
19
- options[:nx] = nx unless nx.nil?
20
- options[:xx] = xx unless xx.nil?
21
-
22
- self.connection.set(@key, value, options) == 'OK'
23
- end
24
-
25
- # @param [::String] value The value to compare with
26
- # @return [Boolean] True if deleted, false otherwise
27
- def delete_if_equals(value)
28
- coerce_bool(delete_if_equals_script(keys: @key, argv: value))
29
- end
30
-
31
- # @param [Object] value The object to store; note, it will be stored using a string representation
32
- # @return [::String] The old value before setting it
33
- def getset(value)
34
- self.connection.getset(@key, value)
35
- end
36
-
37
- # @return [Fixnum] The length of the string
38
- def length
39
- self.connection.strlen(@key)
40
- end
41
-
42
- # @param [Fixnum] start Starting index of the slice
43
- # @param [Fixnum] length Length of the slice; negative numbers start counting from the right (-1 = end)
44
- # @return [Array<::String>] The requested slice from <start> with length <length>
45
- def slice(start = 0, length = -1)
46
- length = start + length if length >= 0
47
- return self.connection.getrange(@key, start, length)
48
- end
49
-
50
- # Deletes the key (keys[1]) iff the value is equal to argv[1].
51
- # @param [Array<(::String)>] keys The key to delete
52
- # @param [Array<(::String)>] argv The value to compare with
53
- # @return [Fixnum] 1 if deleted, 0 otherwise
54
- defscript :delete_if_equals_script, <<~LUA
55
- local deleted = false
56
- if redis.call("get", KEYS[1]) == ARGV[1] then
57
- deleted = redis.call("del", KEYS[1])
58
- end
59
-
60
- return deleted
61
- LUA
62
- end
63
- end
64
- end
@@ -1,58 +0,0 @@
1
- require 'forwardable'
2
-
3
- module Redstruct
4
- module Types
5
- class Struct < Redstruct::Types::Base
6
- include Redstruct::Utils::Inspectable
7
-
8
- # @return [Boolean] Returns true if it exists in redis, false otherwise
9
- def exists?
10
- return self.connection.exists(@key)
11
- end
12
-
13
- # @return [Fixnum] 0 if nothing was deleted in the DB, 1 if it was
14
- def delete
15
- self.connection.del(@key)
16
- end
17
-
18
- # Sets the key to expire after ttl seconds
19
- # @param [Integer, #to_i] ttl the time to live in seconds (or milliseconds if ms is true)
20
- # @param [Boolean] ms if true, assumes ttl is in milliseconds
21
- def expire(ttl, ms: false)
22
- if ms
23
- self.connection.pexpire(@key, ttl.to_i)
24
- else
25
- self.connection.expire(@key, ttl.to_i)
26
- end
27
- end
28
-
29
- # Sets the key to expire at the given timestamp.
30
- # @param [Time, Integer, #to_i] time time or unix timestamp at which the key should expire
31
- # @param [Boolean] ms if true, assumes the timestamp is in milliseconds
32
- def expire_at(time, ms: false)
33
- if ms
34
- time = (time.to_f * 1000) if time.is_a?(Time)
35
- self.connection.pexpireat(@key, time.to_i)
36
- else
37
- self.connection.expireat(@key, time.to_i)
38
- end
39
- end
40
-
41
- # Removes the expiry time from a key
42
- def persist
43
- self.connection.persist(@key)
44
- end
45
-
46
- # @return [String] the underlying redis type
47
- def type
48
- self.connection.type(@key)
49
- end
50
-
51
- # :nocov:
52
- def inspectable_attributes
53
- super.merge(key: @key)
54
- end
55
- # :nocov:
56
- end
57
- end
58
- end
@@ -1,15 +0,0 @@
1
- require 'logger'
2
-
3
- module Releaser
4
- class Logger < ::Logger
5
- TAG = '[RELEASER]'.freeze
6
-
7
- def info(message)
8
- super(TAG) { message }
9
- end
10
-
11
- def error(message)
12
- super(TAG) { message }
13
- end
14
- end
15
- end
@@ -1,32 +0,0 @@
1
- require 'english'
2
-
3
- module Releaser
4
- class Repository
5
- attr_reader :path
6
-
7
- def initialize(path = '.')
8
- @path = File.expand_path(path)
9
- raise(Error, 'Unreadable path given') unless File.readable?(@path)
10
- raise(Error, 'Repository is not a directory') unless File.directory?(@path)
11
- raise(Error, 'Repository is not a github repository') unless git?
12
- end
13
-
14
- def git?
15
- File.directory?("#{@path}/.git")
16
- end
17
-
18
- def clean?
19
- committed = `git status -s`.chomp.strip.empty?
20
- pushed = `git log origin/master..HEAD`.chomp.strip.empty?
21
-
22
- return committed && pushed
23
- end
24
-
25
- def fetch_remote_tags
26
- `git fetch --tags`
27
- return $CHILD_STATUS.success?
28
- end
29
-
30
- class Error < StandardError; end
31
- end
32
- end