duranged 0.0.1 → 0.0.2
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 +4 -4
- data/lib/duranged.rb +2 -0
- data/lib/duranged/base.rb +11 -136
- data/lib/duranged/formatters.rb +108 -0
- data/lib/duranged/occurrence.rb +41 -18
- data/lib/duranged/periods.rb +66 -0
- data/lib/duranged/range.rb +19 -22
- data/lib/duranged/version.rb +1 -1
- data/spec/spec_helper.rb +2 -2
- metadata +8 -4
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 46db5544d738bea7c2e616f797e6667e817cd9a1
         | 
| 4 | 
            +
              data.tar.gz: e7fe1eae2d4205fc344175e7ea9f9298549e77fd
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: c38eba26ed2b9208cd0c95bfa61224287940af2cf5f92bc0b4604bf1dc8ef762d63a9a1103d5ec38d79fe46cb59287b0a3e151a948b375b33eec24f18911e979
         | 
| 7 | 
            +
              data.tar.gz: 2a7319101bfb44860c33ead635bac7d27634c6a0f62ab8c56057cf83dfc6734e51d0d5cdf25269c806c9a089bc9b1c0e24e54ea20c326aadff7c320ac107b9ff
         | 
    
        data/lib/duranged.rb
    CHANGED
    
    | @@ -5,6 +5,8 @@ require 'active_support/core_ext/numeric' | |
| 5 5 | 
             
            require 'active_support/core_ext/time'
         | 
| 6 6 | 
             
            require 'canfig'
         | 
| 7 7 | 
             
            require 'chronic_duration'
         | 
| 8 | 
            +
            require 'duranged/periods'
         | 
| 9 | 
            +
            require 'duranged/formatters'
         | 
| 8 10 | 
             
            require 'duranged/base'
         | 
| 9 11 | 
             
            require 'duranged/duration'
         | 
| 10 12 | 
             
            require 'duranged/interval'
         | 
    
        data/lib/duranged/base.rb
    CHANGED
    
    | @@ -1,17 +1,10 @@ | |
| 1 1 | 
             
            module Duranged
         | 
| 2 2 | 
             
              class Base
         | 
| 3 3 | 
             
                include Comparable
         | 
| 4 | 
            -
                 | 
| 4 | 
            +
                include Periods
         | 
| 5 | 
            +
                include Formatters
         | 
| 5 6 |  | 
| 6 | 
            -
                 | 
| 7 | 
            -
                FORMATTERS = { 's' => -> (pad,with) { pad_value seconds, pad, with },
         | 
| 8 | 
            -
                               'm' => -> (pad,with) { pad_value minutes, pad, with },
         | 
| 9 | 
            -
                               'h' => -> (pad,with) { pad_value hours, pad, with },
         | 
| 10 | 
            -
                               'd' => -> (pad,with) { pad_value days, pad, with },
         | 
| 11 | 
            -
                               'D' => -> (pad,with) { pad_value days_after_weeks, pad, with },
         | 
| 12 | 
            -
                               'w' => -> (pad,with) { pad_value weeks, pad, with },
         | 
| 13 | 
            -
                               'M' => -> (pad,with) { pad_value months, pad, with },
         | 
| 14 | 
            -
                               'y' => -> (pad,with) { pad_value years, pad, with } }
         | 
| 7 | 
            +
                attr_reader :value
         | 
| 15 8 |  | 
| 16 9 | 
             
                class << self
         | 
| 17 10 | 
             
                  def dump(obj)
         | 
| @@ -35,118 +28,6 @@ module Duranged | |
| 35 28 | 
             
                  end
         | 
| 36 29 | 
             
                end
         | 
| 37 30 |  | 
| 38 | 
            -
                def years
         | 
| 39 | 
            -
                  (value.to_f / 60 / 60 / 24 / 365.25).to_i
         | 
| 40 | 
            -
                end
         | 
| 41 | 
            -
             | 
| 42 | 
            -
                def months
         | 
| 43 | 
            -
                  ((value - years.years) / 60 / 60 / 24 / 30).floor
         | 
| 44 | 
            -
                end
         | 
| 45 | 
            -
             | 
| 46 | 
            -
                def weeks
         | 
| 47 | 
            -
                  (((value - months.months - years.years) / 60 / 60 / 24).floor / 7).floor
         | 
| 48 | 
            -
                end
         | 
| 49 | 
            -
             | 
| 50 | 
            -
                def days_after_weeks
         | 
| 51 | 
            -
                  ((value - weeks.weeks - months.months - years.years) / 60 / 60 / 24).floor
         | 
| 52 | 
            -
                end
         | 
| 53 | 
            -
             | 
| 54 | 
            -
                def days
         | 
| 55 | 
            -
                  ((value - months.months - years.years) / 60 / 60 / 24).floor
         | 
| 56 | 
            -
                end
         | 
| 57 | 
            -
             | 
| 58 | 
            -
                def hours
         | 
| 59 | 
            -
                  ((value - days.days - months.months - years.years) / 60 / 60).floor
         | 
| 60 | 
            -
                end
         | 
| 61 | 
            -
             | 
| 62 | 
            -
                def minutes
         | 
| 63 | 
            -
                  ((value - hours.hours - days.days - months.months - years.years) / 60).floor
         | 
| 64 | 
            -
                end
         | 
| 65 | 
            -
             | 
| 66 | 
            -
                def seconds
         | 
| 67 | 
            -
                  (value - minutes.minutes - hours.hours - days.days - months.months - years.years).floor
         | 
| 68 | 
            -
                end
         | 
| 69 | 
            -
             | 
| 70 | 
            -
                def +(other)
         | 
| 71 | 
            -
                  if other.is_a?(Duration) || other.is_a?(Interval)
         | 
| 72 | 
            -
                    Duranged.logger.warn "Warning: You are adding a #{other.class.name} to a #{self.class.name}, which will result in a #{self.class.name}. If you would like a #{other.class.name} object to be returned you must add your #{self.class.name} to your #{other.class.name} instead." if other.is_a?(Range)
         | 
| 73 | 
            -
                    self.class.new(value + other.value)
         | 
| 74 | 
            -
                  elsif other.is_a?(Integer)
         | 
| 75 | 
            -
                    self.class.new(value + other)
         | 
| 76 | 
            -
                  else
         | 
| 77 | 
            -
                    raise ArgumentError, "value must be an Integer, Duranged::Duration or Duranged::Interval"
         | 
| 78 | 
            -
                  end
         | 
| 79 | 
            -
                end
         | 
| 80 | 
            -
             | 
| 81 | 
            -
                def -(other)
         | 
| 82 | 
            -
                  if other.is_a?(Duration) || other.is_a?(Interval)
         | 
| 83 | 
            -
                    Duranged.logger.warn "Warning: You are subtracting a #{other.class.name} from a #{self.class.name}, which will result in a #{self.class.name}. If you would like a #{other.class.name} object to be returned you must subtract your #{self.class.name} from your #{other.class.name} instead." if other.is_a?(Range)
         | 
| 84 | 
            -
                    self.class.new(value - other.value)
         | 
| 85 | 
            -
                  elsif other.is_a?(Integer)
         | 
| 86 | 
            -
                    self.class.new(value - other)
         | 
| 87 | 
            -
                  else
         | 
| 88 | 
            -
                    raise ArgumentError, "value must be an Integer, Duranged::Duration or Duranged::Interval"
         | 
| 89 | 
            -
                  end
         | 
| 90 | 
            -
                end
         | 
| 91 | 
            -
             | 
| 92 | 
            -
                def as_json(options=nil)
         | 
| 93 | 
            -
                  value
         | 
| 94 | 
            -
                end
         | 
| 95 | 
            -
             | 
| 96 | 
            -
                def to_h
         | 
| 97 | 
            -
                  PARTS.map do |part|
         | 
| 98 | 
            -
                    [part, send(part)]
         | 
| 99 | 
            -
                  end.to_h
         | 
| 100 | 
            -
                end
         | 
| 101 | 
            -
             | 
| 102 | 
            -
                def to_s
         | 
| 103 | 
            -
                  ChronicDuration.output(value, format: :long, joiner: ', ').to_s
         | 
| 104 | 
            -
                end
         | 
| 105 | 
            -
             | 
| 106 | 
            -
                def strfdur(format)
         | 
| 107 | 
            -
                  str = format.to_s
         | 
| 108 | 
            -
             | 
| 109 | 
            -
                  # :years(%Y years, ):months(%N months, )%D :days
         | 
| 110 | 
            -
                  PARTS.each do |part|
         | 
| 111 | 
            -
                    while matches = str.match(/:(#{part})(\((.+)\))?/i) do
         | 
| 112 | 
            -
                      if matches[3]
         | 
| 113 | 
            -
                        # only replaces if the value is > 0, otherwise blank
         | 
| 114 | 
            -
                        matched = ''
         | 
| 115 | 
            -
                        depth = 0
         | 
| 116 | 
            -
                        matches[3].chars.to_a.each do |char|
         | 
| 117 | 
            -
                          depth += 1 if char == '('
         | 
| 118 | 
            -
                          depth -= 1 if char == ')'
         | 
| 119 | 
            -
                          break if depth == -1
         | 
| 120 | 
            -
                          matched += char
         | 
| 121 | 
            -
                        end
         | 
| 122 | 
            -
                        value = send(part) > 0 ? strfdur(matched.dup) : ''
         | 
| 123 | 
            -
                        str.gsub!(":#{part}(#{matched})", value)
         | 
| 124 | 
            -
                      else
         | 
| 125 | 
            -
                        # if no nested format was passed, replace with a singular
         | 
| 126 | 
            -
                        # or plural part name as appropriate
         | 
| 127 | 
            -
                        value = send(part) == 1 ? matches[1].to_s.singularize : matches[1].to_s
         | 
| 128 | 
            -
                        str.gsub!(matches[0], value)
         | 
| 129 | 
            -
                      end
         | 
| 130 | 
            -
                    end
         | 
| 131 | 
            -
                  end
         | 
| 132 | 
            -
             | 
| 133 | 
            -
                  FORMATTERS.each do |conversion, block|
         | 
| 134 | 
            -
                    while matches = str.match(/%([-_])?([0-9]+)?(#{conversion})/) do
         | 
| 135 | 
            -
                      pad_with = matches[1] == '_' ? :space : :zero
         | 
| 136 | 
            -
                      value = instance_exec(matches[2] || 2, pad_with, &block)
         | 
| 137 | 
            -
                      value = value.to_i.to_s.lstrip if matches[1] == '-'
         | 
| 138 | 
            -
             | 
| 139 | 
            -
                      str.gsub!(matches[0], value)
         | 
| 140 | 
            -
                    end
         | 
| 141 | 
            -
                  end
         | 
| 142 | 
            -
             | 
| 143 | 
            -
                  str
         | 
| 144 | 
            -
                end
         | 
| 145 | 
            -
             | 
| 146 | 
            -
                def to_i
         | 
| 147 | 
            -
                  value
         | 
| 148 | 
            -
                end
         | 
| 149 | 
            -
             | 
| 150 31 | 
             
                def <=>(other)
         | 
| 151 32 | 
             
                  if value < other.to_i
         | 
| 152 33 | 
             
                    -1
         | 
| @@ -157,8 +38,14 @@ module Duranged | |
| 157 38 | 
             
                  end
         | 
| 158 39 | 
             
                end
         | 
| 159 40 |  | 
| 160 | 
            -
                def  | 
| 161 | 
            -
                   | 
| 41 | 
            +
                def +(other)
         | 
| 42 | 
            +
                  Duranged.logger.warn "Warning: You are adding a #{other.class.name} to a #{self.class.name}, which will result in a #{self.class.name}. If you would like a #{other.class.name} object to be returned you must add your #{self.class.name} to your #{other.class.name} instead." if other.is_a?(Range)
         | 
| 43 | 
            +
                  self.class.new(to_i + other.to_i)
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                def -(other)
         | 
| 47 | 
            +
                  Duranged.logger.warn "Warning: You are subtracting a #{other.class.name} from a #{self.class.name}, which will result in a #{self.class.name}. If you would like a #{other.class.name} object to be returned you must subtract your #{self.class.name} from your #{other.class.name} instead." if other.is_a?(Range)
         | 
| 48 | 
            +
                  self.class.new(to_i - other.to_i)
         | 
| 162 49 | 
             
                end
         | 
| 163 50 |  | 
| 164 51 | 
             
                protected
         | 
| @@ -166,17 +53,5 @@ module Duranged | |
| 166 53 | 
             
                def parse_hash(hash)
         | 
| 167 54 | 
             
                  hash.sum { |k,v| v.to_i.send(k.to_sym) }
         | 
| 168 55 | 
             
                end
         | 
| 169 | 
            -
             | 
| 170 | 
            -
                def pad_value(value, pad=2, with=:zero)
         | 
| 171 | 
            -
                  send("#{with}_pad".to_sym, value, pad)
         | 
| 172 | 
            -
                end
         | 
| 173 | 
            -
             | 
| 174 | 
            -
                def zero_pad(value, pad=2)
         | 
| 175 | 
            -
                  "%0#{pad}d" % value
         | 
| 176 | 
            -
                end
         | 
| 177 | 
            -
             | 
| 178 | 
            -
                def space_pad(value, pad=2)
         | 
| 179 | 
            -
                  "%#{pad}d" % value
         | 
| 180 | 
            -
                end
         | 
| 181 56 | 
             
              end
         | 
| 182 57 | 
             
            end
         | 
| @@ -0,0 +1,108 @@ | |
| 1 | 
            +
            module Duranged
         | 
| 2 | 
            +
              module Formatters
         | 
| 3 | 
            +
                PERIODS = [:years, :months, :weeks, :days_after_weeks, :days, :hours, :minutes, :seconds]
         | 
| 4 | 
            +
                FORMATTERS = { 's' => -> (pad,with) { pad_value seconds, pad, with },
         | 
| 5 | 
            +
                               'm' => -> (pad,with) { pad_value minutes, pad, with },
         | 
| 6 | 
            +
                               'h' => -> (pad,with) { pad_value hours, pad, with },
         | 
| 7 | 
            +
                               'd' => -> (pad,with) { pad_value days, pad, with },
         | 
| 8 | 
            +
                               'D' => -> (pad,with) { pad_value days_after_weeks, pad, with },
         | 
| 9 | 
            +
                               'w' => -> (pad,with) { pad_value weeks, pad, with },
         | 
| 10 | 
            +
                               'M' => -> (pad,with) { pad_value months, pad, with },
         | 
| 11 | 
            +
                               'y' => -> (pad,with) { pad_value years, pad, with } }
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def as_json(options=nil)
         | 
| 14 | 
            +
                  value
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def to_h
         | 
| 18 | 
            +
                  Hash[PERIODS.map do |part|
         | 
| 19 | 
            +
                    [part, send(part)]
         | 
| 20 | 
            +
                  end]
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                def to_s
         | 
| 24 | 
            +
                  ChronicDuration.output(value, format: :long, joiner: ', ').to_s
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                def strfdur(format)
         | 
| 28 | 
            +
                  str = format.to_s
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  # :years(%Y years, ):months(%N months, )%D :days
         | 
| 31 | 
            +
                  str = strfparts(str)
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                  # %y %M %w %d %m %s
         | 
| 34 | 
            +
                  str = strfformatters(str)
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  str
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                def to_i
         | 
| 40 | 
            +
                  value
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                protected
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                def strfparts(str)
         | 
| 46 | 
            +
                  PERIODS.each do |part|
         | 
| 47 | 
            +
                    while matches = str.match(/:(#{part})(\((.+)\))?/i) do
         | 
| 48 | 
            +
                      if matches[3]
         | 
| 49 | 
            +
                        str = strfpart(str, part)
         | 
| 50 | 
            +
                      else
         | 
| 51 | 
            +
                        # if no nested format was passed, replace with a singular
         | 
| 52 | 
            +
                        # or plural part name as appropriate
         | 
| 53 | 
            +
                        value = send(part) == 1 ? matches[1].to_s.singularize : matches[1].to_s
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                        str.gsub!(matches[0], value)
         | 
| 56 | 
            +
                      end
         | 
| 57 | 
            +
                    end
         | 
| 58 | 
            +
                  end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                  str
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                def strfpart(str, part)
         | 
| 64 | 
            +
                  matched = parse_match(str)
         | 
| 65 | 
            +
                  value = send(part) > 0 ? strfdur(matched.dup) : ''
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                  str.gsub!(":#{part}(#{matched})", value)
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                def strfformatters(str)
         | 
| 71 | 
            +
                  FORMATTERS.each do |conversion, block|
         | 
| 72 | 
            +
                    while matches = str.match(/%([-_])?([0-9]+)?(#{conversion})/) do
         | 
| 73 | 
            +
                      pad_with = matches[1] == '_' ? :space : :zero
         | 
| 74 | 
            +
                      value = instance_exec(matches[2] || 2, pad_with, &block)
         | 
| 75 | 
            +
                      value = value.to_i.to_s.lstrip if matches[1] == '-'
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                      str.gsub!(matches[0], value)
         | 
| 78 | 
            +
                    end
         | 
| 79 | 
            +
                  end
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                  str
         | 
| 82 | 
            +
                end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                def pad_value(value, pad=2, with=:zero)
         | 
| 85 | 
            +
                  send("#{with}_pad".to_sym, value, pad)
         | 
| 86 | 
            +
                end
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                def zero_pad(value, pad=2)
         | 
| 89 | 
            +
                  "%0#{pad}d" % value
         | 
| 90 | 
            +
                end
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                def space_pad(value, pad=2)
         | 
| 93 | 
            +
                  "%#{pad}d" % value
         | 
| 94 | 
            +
                end
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                def parse_match(match_str)
         | 
| 97 | 
            +
                  match_substr = ''
         | 
| 98 | 
            +
                  depth = 0
         | 
| 99 | 
            +
                  match_str.chars.to_a.each do |char|
         | 
| 100 | 
            +
                    depth += 1 if char == '('
         | 
| 101 | 
            +
                    depth -= 1 if char == ')'
         | 
| 102 | 
            +
                    break if depth == -1
         | 
| 103 | 
            +
                    match_substr += char
         | 
| 104 | 
            +
                  end
         | 
| 105 | 
            +
                  match_substr
         | 
| 106 | 
            +
                end
         | 
| 107 | 
            +
              end
         | 
| 108 | 
            +
            end
         | 
    
        data/lib/duranged/occurrence.rb
    CHANGED
    
    | @@ -35,6 +35,15 @@ module Duranged | |
| 35 35 | 
             
                  end
         | 
| 36 36 | 
             
                end
         | 
| 37 37 |  | 
| 38 | 
            +
                def as_json(options=nil)
         | 
| 39 | 
            +
                  hash = { occurrences: occurrences }
         | 
| 40 | 
            +
                  hash[:interval] = interval.as_json(options) if interval
         | 
| 41 | 
            +
                  hash[:duration] = duration.as_json(options) if duration
         | 
| 42 | 
            +
                  hash[:range] = range.as_json(options) if range
         | 
| 43 | 
            +
                  hash
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
                alias_method :to_h, :as_json
         | 
| 46 | 
            +
             | 
| 38 47 | 
             
                def occurrences_string
         | 
| 39 48 | 
             
                  case occurrences
         | 
| 40 49 | 
             
                  when 0
         | 
| @@ -48,15 +57,6 @@ module Duranged | |
| 48 57 | 
             
                  end
         | 
| 49 58 | 
             
                end
         | 
| 50 59 |  | 
| 51 | 
            -
                def as_json(options=nil)
         | 
| 52 | 
            -
                  hash = { occurrences: occurrences }
         | 
| 53 | 
            -
                  hash[:interval] = interval.as_json(options) if interval
         | 
| 54 | 
            -
                  hash[:duration] = duration.as_json(options) if duration
         | 
| 55 | 
            -
                  hash[:range] = range.as_json(options) if range
         | 
| 56 | 
            -
                  hash
         | 
| 57 | 
            -
                end
         | 
| 58 | 
            -
                alias_method :to_h, :as_json
         | 
| 59 | 
            -
             | 
| 60 60 | 
             
                def to_s
         | 
| 61 61 | 
             
                  return occurrences_string if occurrences == 0
         | 
| 62 62 |  | 
| @@ -86,21 +86,28 @@ module Duranged | |
| 86 86 | 
             
                def strfocc(format)
         | 
| 87 87 | 
             
                  str = format.to_s
         | 
| 88 88 |  | 
| 89 | 
            +
                  str = strfoccurrences(str)
         | 
| 90 | 
            +
                  str = strfrange(str)
         | 
| 91 | 
            +
                  str = strfdurint(str)
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                  str
         | 
| 94 | 
            +
                end
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                protected
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                def strfoccurrences(str)
         | 
| 89 99 | 
             
                  while matches = str.match(/:occurrence[s]?/) do
         | 
| 90 100 | 
             
                    str.gsub!(matches[0], occurrences.to_s)
         | 
| 91 101 | 
             
                  end
         | 
| 92 | 
            -
             | 
| 102 | 
            +
             | 
| 103 | 
            +
                  str
         | 
| 104 | 
            +
                end
         | 
| 105 | 
            +
             | 
| 106 | 
            +
                def strfrange(str)
         | 
| 93 107 | 
             
                  if range
         | 
| 94 108 | 
             
                    while matches = str.match(/:range(\((.+)\))?/) do
         | 
| 95 109 | 
             
                      if matches[2]
         | 
| 96 | 
            -
                        matched =  | 
| 97 | 
            -
                        depth = 0
         | 
| 98 | 
            -
                        matches[2].chars.to_a.each do |char|
         | 
| 99 | 
            -
                          depth += 1 if char == '('
         | 
| 100 | 
            -
                          depth -= 1 if char == ')'
         | 
| 101 | 
            -
                          break if depth == -1
         | 
| 102 | 
            -
                          matched += char
         | 
| 103 | 
            -
                        end
         | 
| 110 | 
            +
                        matched = parse_match(matches[2])
         | 
| 104 111 | 
             
                        value = range.strfrange(matched.dup)
         | 
| 105 112 | 
             
                        str.gsub!(":range(#{matched})", value)
         | 
| 106 113 | 
             
                      else
         | 
| @@ -110,6 +117,10 @@ module Duranged | |
| 110 117 | 
             
                    end
         | 
| 111 118 | 
             
                  end
         | 
| 112 119 |  | 
| 120 | 
            +
                  str
         | 
| 121 | 
            +
                end
         | 
| 122 | 
            +
             | 
| 123 | 
            +
                def strfdurint(str)
         | 
| 113 124 | 
             
                  if duration || interval
         | 
| 114 125 | 
             
                    while matches = str.match(/:(duration|interval)(\(([^\)]+)\))/) do
         | 
| 115 126 | 
             
                      matched = send(matches[1])
         | 
| @@ -120,5 +131,17 @@ module Duranged | |
| 120 131 |  | 
| 121 132 | 
             
                  str
         | 
| 122 133 | 
             
                end
         | 
| 134 | 
            +
             | 
| 135 | 
            +
                def parse_match(match_str)
         | 
| 136 | 
            +
                  match_substr = ''
         | 
| 137 | 
            +
                  depth = 0
         | 
| 138 | 
            +
                  match_str.chars.to_a.each do |char|
         | 
| 139 | 
            +
                    depth += 1 if char == '('
         | 
| 140 | 
            +
                    depth -= 1 if char == ')'
         | 
| 141 | 
            +
                    break if depth == -1
         | 
| 142 | 
            +
                    match_substr += char
         | 
| 143 | 
            +
                  end
         | 
| 144 | 
            +
                  match_substr
         | 
| 145 | 
            +
                end
         | 
| 123 146 | 
             
              end
         | 
| 124 147 | 
             
            end
         | 
| @@ -0,0 +1,66 @@ | |
| 1 | 
            +
            module Duranged
         | 
| 2 | 
            +
              module Periods
         | 
| 3 | 
            +
                def years
         | 
| 4 | 
            +
                  (value.to_f / 60 / 60 / 24 / 365.25).to_i
         | 
| 5 | 
            +
                end
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def months
         | 
| 8 | 
            +
                  (seconds_after_years / 60 / 60 / 24 / 30).floor
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def weeks
         | 
| 12 | 
            +
                  ((seconds_after_months / 60 / 60 / 24).floor / 7).floor
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def days_after_weeks
         | 
| 16 | 
            +
                  (seconds_after_weeks / 60 / 60 / 24).floor
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def days_after_months
         | 
| 20 | 
            +
                  (seconds_after_months / 60 / 60 / 24).floor
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                def days
         | 
| 24 | 
            +
                  # TODO make this a configuration option with the ability to default to :days_after_weeks
         | 
| 25 | 
            +
                  days_after_months
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                def hours
         | 
| 29 | 
            +
                  (seconds_after_days / 60 / 60).floor
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                def minutes
         | 
| 33 | 
            +
                  (seconds_after_hours / 60).floor
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                def seconds
         | 
| 37 | 
            +
                  seconds_after_minutes.floor
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                protected
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                def seconds_after_years
         | 
| 43 | 
            +
                  value - years.years
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                def seconds_after_months
         | 
| 47 | 
            +
                  seconds_after_years - months.months
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                def seconds_after_weeks
         | 
| 51 | 
            +
                  seconds_after_months - weeks.weeks
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                def seconds_after_days
         | 
| 55 | 
            +
                  seconds_after_months - days.days
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                def seconds_after_hours
         | 
| 59 | 
            +
                  seconds_after_days - hours.hours
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                def seconds_after_minutes
         | 
| 63 | 
            +
                  seconds_after_hours - minutes.minutes
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
              end
         | 
| 66 | 
            +
            end
         | 
    
        data/lib/duranged/range.rb
    CHANGED
    
    | @@ -49,23 +49,11 @@ module Duranged | |
| 49 49 | 
             
                alias_method :end_time, :end_at
         | 
| 50 50 |  | 
| 51 51 | 
             
                def +(other)
         | 
| 52 | 
            -
                   | 
| 53 | 
            -
                    self.class.new(start_at, value + other.value)
         | 
| 54 | 
            -
                  elsif other.is_a?(Integer)
         | 
| 55 | 
            -
                    self.class.new(start_at, value + other)
         | 
| 56 | 
            -
                  else
         | 
| 57 | 
            -
                    raise ArgumentError, "value must be an Integer, Duranged::Duration or Duranged::Interval"
         | 
| 58 | 
            -
                  end
         | 
| 52 | 
            +
                  self.class.new(start_at, to_i + other.to_i)
         | 
| 59 53 | 
             
                end
         | 
| 60 54 |  | 
| 61 55 | 
             
                def -(other)
         | 
| 62 | 
            -
                   | 
| 63 | 
            -
                    self.class.new(start_at, value - other.value)
         | 
| 64 | 
            -
                  elsif other.is_a?(Integer)
         | 
| 65 | 
            -
                    self.class.new(start_at, value - other)
         | 
| 66 | 
            -
                  else
         | 
| 67 | 
            -
                    raise ArgumentError, "value must be an Integer, Duranged::Duration or Duranged::Interval"
         | 
| 68 | 
            -
                  end
         | 
| 56 | 
            +
                  self.class.new(start_at, to_i - other.to_i)
         | 
| 69 57 | 
             
                end
         | 
| 70 58 |  | 
| 71 59 | 
             
                def to_duration
         | 
| @@ -89,23 +77,32 @@ module Duranged | |
| 89 77 | 
             
                def strfrange(format)
         | 
| 90 78 | 
             
                  str = format.to_s
         | 
| 91 79 |  | 
| 80 | 
            +
                  str = strfstartend(str)
         | 
| 81 | 
            +
                  str = strfduration(str)
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                  str
         | 
| 84 | 
            +
                end
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                def same_day?
         | 
| 87 | 
            +
                  start_at('%j') == end_at('%j')
         | 
| 88 | 
            +
                end
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                protected
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                def strfstartend(str)
         | 
| 92 93 | 
             
                  while matches = str.match(/:(start_at|end_at|)\((([^\)]+))\)/) do
         | 
| 93 94 | 
             
                    str.gsub!(matches[0], send(matches[1], matches[2]))
         | 
| 94 95 | 
             
                  end
         | 
| 95 96 |  | 
| 97 | 
            +
                  str
         | 
| 98 | 
            +
                end
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                def strfduration(str)
         | 
| 96 101 | 
             
                  while matches = str.match(/:duration\(([^\)]+)\)/) do
         | 
| 97 102 | 
             
                    str.gsub!(matches[0], strfdur(matches[1]))
         | 
| 98 103 | 
             
                  end
         | 
| 99 104 |  | 
| 100 105 | 
             
                  str
         | 
| 101 106 | 
             
                end
         | 
| 102 | 
            -
             | 
| 103 | 
            -
                def call
         | 
| 104 | 
            -
                  to_s
         | 
| 105 | 
            -
                end
         | 
| 106 | 
            -
             | 
| 107 | 
            -
                def same_day?
         | 
| 108 | 
            -
                  start_at('%j') == end_at('%j')
         | 
| 109 | 
            -
                end
         | 
| 110 107 | 
             
              end
         | 
| 111 108 | 
             
            end
         | 
    
        data/lib/duranged/version.rb
    CHANGED
    
    
    
        data/spec/spec_helper.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: duranged
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.0. | 
| 4 | 
            +
              version: 0.0.2
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Mark Rebec
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2015-10- | 
| 11 | 
            +
            date: 2015-10-13 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: activesupport
         | 
| @@ -80,7 +80,8 @@ dependencies: | |
| 80 80 | 
             
                - - ">="
         | 
| 81 81 | 
             
                  - !ruby/object:Gem::Version
         | 
| 82 82 | 
             
                    version: '0'
         | 
| 83 | 
            -
            description:  | 
| 83 | 
            +
            description: A set of classes to facilitate working with and formatting durations,
         | 
| 84 | 
            +
              intervals, time ranges and occurrences.
         | 
| 84 85 | 
             
            email:
         | 
| 85 86 | 
             
            - mark@markrebec.com
         | 
| 86 87 | 
             
            executables: []
         | 
| @@ -90,8 +91,10 @@ files: | |
| 90 91 | 
             
            - lib/duranged.rb
         | 
| 91 92 | 
             
            - lib/duranged/base.rb
         | 
| 92 93 | 
             
            - lib/duranged/duration.rb
         | 
| 94 | 
            +
            - lib/duranged/formatters.rb
         | 
| 93 95 | 
             
            - lib/duranged/interval.rb
         | 
| 94 96 | 
             
            - lib/duranged/occurrence.rb
         | 
| 97 | 
            +
            - lib/duranged/periods.rb
         | 
| 95 98 | 
             
            - lib/duranged/range.rb
         | 
| 96 99 | 
             
            - lib/duranged/version.rb
         | 
| 97 100 | 
             
            - spec/duranged/base_spec.rb
         | 
| @@ -124,7 +127,8 @@ rubyforge_project: | |
| 124 127 | 
             
            rubygems_version: 2.2.2
         | 
| 125 128 | 
             
            signing_key: 
         | 
| 126 129 | 
             
            specification_version: 4
         | 
| 127 | 
            -
            summary:  | 
| 130 | 
            +
            summary: A set of classes to facilitate working with and formatting durations, intervals,
         | 
| 131 | 
            +
              time ranges and occurrences.
         | 
| 128 132 | 
             
            test_files:
         | 
| 129 133 | 
             
            - spec/duranged/base_spec.rb
         | 
| 130 134 | 
             
            - spec/duranged/duration_spec.rb
         |