Module: EasyAttributes

Defined in:
lib/easy_attributes.rb

Overview

Mixes in attr_* definitions into ruby classes for using symbolic names as values, money, and bytes

Defined Under Namespace

Modules: ClassMethods Classes: Config

Constant Summary collapse

KB =

Official Definitions for kilobyte and kibibyte quantity prefixes

1000
MB =
KB **2
GB =
KB **3
TB =
KB **4
PB =
KB **5
EB =
KB **6
ZB =
KB **7
YB =
KB **8
KiB =
1024
MiB =
KiB**2
GiB =
KiB**3
TiB =
KiB**4
PiB =
KiB**5
EiB =
KiB**6
ZiB =
KiB**7
YiB =
KiB**8
DECIMAL_PREFIXES =
{:B=>1, :KB=>KB, :MB=>MB, :GB=>GB, :TB=>TB, :PB=>PB, :EB=>EB, :ZB=>ZB, :TB=>YB}
BINARY_PREFIXES =
{:B=>1, :KiB=>KiB, :MiB=>MiB, :GiB=>GiB, :TiB=>TiB, :PiB=>PiB, :EiB=>EiB, :ZiB=>ZiB, :TiB=>YiB}

Class Method Summary collapse

Class Method Details

.add_definition(attribute, hash, opt = {}) ⇒ Object



197
198
199
# File 'lib/easy_attributes.rb', line 197

def self.add_definition(attribute, hash, opt={})
  EasyAttributes::Config.define attribute, hash
end

.byte_prefixes(kb_size = 0) ⇒ Object

Returns a hash of prefix names to decimal quantities for the given setting



248
249
250
251
252
253
254
255
# File 'lib/easy_attributes.rb', line 248

def self.byte_prefixes(kb_size=0)
  case kb_size
  when 1000, :decimal, :si then DECIMAL_PREFIXES
  when :old, :jedec, 1024 then {:KB=>KiB, :MB=>MiB, :GB=>GiB, :TB=>TiB, :PB=>PiB, :EB=>EiB, :ZB=>ZiB, :TB=>YiB}
  when :new, :iec then BINARY_PREFIXES
  else DECIMAL_PREFIXES.merge(BINARY_PREFIXES) # Both? What's the least surprise?
  end
end

.float_to_integer(value, *args) ⇒ Object

Returns the integer (cents) value from a Float



358
359
360
361
362
# File 'lib/easy_attributes.rb', line 358

def self.float_to_integer(value, *args)
  opt = args.last.is_a?(Hash) ? args.pop : {}
  return (opt[:blank]||nil) if value.nil?
  value = (value.to_f*(10**((opt[:precision]||2)+1))).to_i/10 # helps rounding 4.56 -> 455 ouch!
end

.format_bytes(v, *args) ⇒ Object

Takes a number of bytes and an optional :unit argument and :precision option, returns a formatted string of units



258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
# File 'lib/easy_attributes.rb', line 258

def self.format_bytes(v, *args)
  opt = EasyAttributes.pop_options(args, :precision=>3)
  prefixes = EasyAttributes.byte_prefixes(opt[:kb_size]||EasyAttributes::Config.kb_size||0)
  if args.size > 0 && args.first.is_a?(Symbol)
    (unit, precision) = args
    v = "%.#{precision||opt[:precision]}f" % (1.0 * v / (prefixes[unit]||1))
    return "#{v} #{unit}"
  else
    precision = args.shift || opt[:precision]
    prefixes.sort{|a,b| a[1]<=>b[1]}.reverse.each do |pv|
      next if pv[1] > v
      v = "%f.10f" % (1.0 * v / pv[1])
      v = v[0,precision+1] if v =~ /^(\d)+\.(\d+)/ && v.size > (precision+1)
      v.gsub!(/\.0*$/, '')
      return "#{v} #{pv[0]}"
    end
  end
  v.to_s
end

.format_money(value, pattern = "%.2m", *args) ⇒ Object

Replacing the sprintf function to deal with money as float. “… %[flags]m …”



365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
# File 'lib/easy_attributes.rb', line 365

def self.format_money(value, pattern="%.2m", *args)
  opt = args.last.is_a?(Hash) ? args.pop : {}
  sign = value < 0 ? -1 : 1
  dollars, cents = value.abs.divmod( 10 ** (opt[:precision]||2))
  dollars *= sign
  parts = pattern.match(/^(.*)%([-\. \d+0]*)[fm](.*)/)
  return pattern unless parts
  intdec = parts[2].match(/(.*)\.(\d*)/)
  dprec, cprec = intdec ? [intdec[1], intdec[2]] : ['', '']
  dollars = sprintf("%#{dprec}d", dollars)
  cents = '0' + cents.to_s while cents.to_s.length < (opt[:precision]||2)
  cents = cents.to_s[0,cprec.to_i]
  cents = cents + '0' while cents.length < cprec.to_i
  value = parts[1] + "#{(dollars.to_i==0 && sign==-1) ? '-' : '' }#{dollars}#{cents>' '? '.':''}#{cents}" + parts[3]
  value
end

.getter_setter(attribute) ⇒ Object

Returns a [getter_code, setter_code] depending on the orm configuration



185
186
187
188
189
190
191
# File 'lib/easy_attributes.rb', line 185

def self.getter_setter(attribute)
  if EasyAttributes::Config.orm == :active_model
    ["self.attributes[:#{attribute}]", "self.write_attribute(:#{attribute}, v)"]
  else
    ["@#{attribute}", "@#{attribute} = v"]
  end
end

.included(base) ⇒ Object

:nodoc:



4
5
6
# File 'lib/easy_attributes.rb', line 4

def self.included(base) #:nodoc:
  base.extend( ClassMethods )
end

.integer_to_float(value, *args) ⇒ Object



330
331
332
333
334
# File 'lib/easy_attributes.rb', line 330

def self.integer_to_float(value, *args)
  opt = args.last.is_a?(Hash) ? args.pop : {}
  return (opt[:blank]||nil) if value.nil?
  value = 1.0 * value / (10**(opt[:precision]||2)) 
end

.integer_to_money(value, *args) ⇒ Object

Returns the money string of the given integer value. Uses relevant options from #easy_money



303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
# File 'lib/easy_attributes.rb', line 303

def self.integer_to_money(value, *args)
  opt = args.last.is_a?(Hash) ? args.pop : {}
  opt[:positive] ||= "%.#{opt[:precision]||2}f"
  pattern = 
    if value.nil?
      value = 0
      opt[:nil] || opt[:positive]
    else
      case value <=> 0
      when 1 then opt[:positive]
      when 0 then opt[:zero] || opt[:positive]
      else  
        value = -value if opt[:negative] && opt[:negative] != opt[:positive]
        opt[:negative] || opt[:positive]
      end
    end
  value = self.format_money( value, pattern, opt)
  value = opt[:unit]+value if opt[:unit]
  value.gsub!(/\./,opt[:separator]) if opt[:separator]
  if opt[:delimiter] && (m = value.match(/^(\D*)(\d+)(.*)/))
    # Adapted From Rails' ActionView::Helpers::NumberHelper
    n = m[2].gsub(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{opt[:delimiter]}")
    value=m[1]+n+m[3]
  end
  value
end

.money_to_integer(value, *args) ⇒ Object

Returns the integer of the given money string. Uses relevant options from #easy_money



337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
# File 'lib/easy_attributes.rb', line 337

def self.money_to_integer(value, *args)
  opt = args.last.is_a?(Hash) ? args.pop : {}
  value = value.gsub(opt[:delimiter],'') if opt[:delimiter]
  value = value.gsub(opt[:separator],'.') if opt[:separator]
  value = value.gsub(/^[^\d\.\-\,]+/,'')
  return (opt[:blank]||nil) unless value =~ /\d/
  m = value.to_s.match(opt[:negative_regex]||/^(-?)(.+\d)\s*cr/i)
  value = value.match(/^-/) ? m[2] : "-#{m[2]}" if m && m[2]

  # Money string ("123.45") to proper integer withough passing through the float transformation
  match = value.match(/(-?\d*)\.?(\d*)/)
  return 0 unless match
  value = match[1].to_i * (10 ** (opt[:precision]||2))
  cents = match[2]
  cents = cents + '0' while cents.length < (opt[:precision]||2)
  cents = cents.to_s[0,opt[:precision]||2]
  value += cents.to_i * (value<0 ? -1 : 1)
  value
end

.parse_bytes(v, *args) ⇒ Object

Takes a string of “number units” or Array of [number, :units] and returns the number of bytes represented.



279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
# File 'lib/easy_attributes.rb', line 279

def self.parse_bytes(v, *args)
  opt = EasyAttributes.pop_options(args, :precision=>3)
  # Handle v= [100, :KB]
  if v.is_a?(Array)
    bytes = v.shift
    v = "#{bytes} #{v.shift}"
  else
    bytes = v.to_f
  end
  
 if v.downcase =~ /^\s*(?:[\d\.]+)\s*([kmgtpezy]i?b)/i
   units = ($1.size==2 ? $1.upcase : $1[0,1].upcase+$1[1,1]+$1[2,1].upcase).to_sym
    prefixes = EasyAttributes.byte_prefixes(opt[:kb_size]||EasyAttributes::Config.kb_size||0)
   bytes *= prefixes[units] if prefixes.has_key?(units)
   #puts "v=#{v} b=#{bytes} u=#{units} #{units.class} bp=#{prefixes[units]} kb=#{opt[:kb_size]} P=#{prefixes.inspect}"
 end
 (bytes*100).to_i/100
end

.pop_options(args, defaults = {}) ⇒ Object



193
194
195
# File 'lib/easy_attributes.rb', line 193

def self.pop_options(args, defaults={})
  args.last.is_a?(Hash) ? defaults.merge(args.pop) : defaults
end

.sym_for_value(attribute, value) ⇒ Object

Returns the defined symbol for the given value on the attribute



212
213
214
215
216
# File 'lib/easy_attributes.rb', line 212

def self.sym_for_value(attribute, value)
  return nil if value.nil?
  EasyAttributes::Config.attributes[attribute].each {|k,v| return k if v==value}
  raise "EasyAttribute #{attribute} symbol not found for #{value}"
end

.value_for_sym(attribute, sym) ⇒ Object

Returns the defined value for the given symbol and attribute



206
207
208
209
# File 'lib/easy_attributes.rb', line 206

def self.value_for_sym(attribute, sym)
  EasyAttributes::Config.attributes[attribute][sym] or 
    raise "EasyAttributes #{attribute} value :#{sym} not declared"
end

.value_is?(attribute, value, *args) ⇒ Boolean

Returns:

  • (Boolean)


218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
# File 'lib/easy_attributes.rb', line 218

def self.value_is?(attribute, value, *args)
  case args.first
  when :between then
    value >= EasyAttributes::Config.attributes[attribute][args[1]] && value <= EasyAttributes::Config.attributes[attribute][args[2]]
  when :gt, :greater_than then
    value > EasyAttributes::Config.attributes[attribute][args[1]]
  when :ge, :greater_than_or_equal_to then
    value >= EasyAttributes::Config.attributes[attribute][args[1]]
  when :lt, :less_than then
    value < EasyAttributes::Config.attributes[attribute][args[1]]
  when :le, :less_than_or_equal_to then
    value <= EasyAttributes::Config.attributes[attribute][args[1]]
  #when :not, :not_in
  #  ! args.include? EasyAttributes::Config.attributes[attribute].keys
  else
    args.include? EasyAttributes.sym_for_value(attribute, value)
  end
end