gorillib 0.4.1pre → 0.4.2pre
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +13 -10
- data/.rspec +1 -1
- data/.yardopts +1 -0
- data/CHANGELOG.md +47 -0
- data/Gemfile +22 -19
- data/Guardfile +23 -9
- data/README.md +12 -12
- data/Rakefile +29 -40
- data/VERSION +1 -1
- data/examples/benchmark/factories_benchmark.rb +87 -0
- data/examples/builder/ironfan.rb +1 -19
- data/examples/hash/slicing_methods.rb +101 -0
- data/gorillib.gemspec +36 -35
- data/lib/gorillib/array/deep_compact.rb +4 -3
- data/lib/gorillib/array/simple_statistics.rb +76 -0
- data/lib/gorillib/base.rb +0 -1
- data/lib/gorillib/builder.rb +15 -30
- data/lib/gorillib/collection.rb +159 -57
- data/lib/gorillib/collection/model_collection.rb +136 -43
- data/lib/gorillib/datetime/parse.rb +4 -2
- data/lib/gorillib/{array → deprecated/array}/average.rb +0 -0
- data/lib/gorillib/{array → deprecated/array}/random.rb +2 -1
- data/lib/gorillib/{array → deprecated/array}/sorted_median.rb +0 -0
- data/lib/gorillib/{array → deprecated/array}/sorted_percentile.rb +0 -0
- data/lib/gorillib/deprecated/array/sorted_sample.rb +13 -0
- data/lib/gorillib/{metaprogramming → deprecated/metaprogramming}/aliasing.rb +0 -0
- data/lib/gorillib/enumerable/sum.rb +3 -3
- data/lib/gorillib/exception/raisers.rb +92 -22
- data/lib/gorillib/factories.rb +550 -0
- data/lib/gorillib/hash/mash.rb +15 -58
- data/lib/gorillib/hashlike/deep_compact.rb +2 -2
- data/lib/gorillib/hashlike/slice.rb +55 -40
- data/lib/gorillib/model.rb +5 -3
- data/lib/gorillib/model/base.rb +33 -119
- data/lib/gorillib/model/defaults.rb +58 -14
- data/lib/gorillib/model/errors.rb +10 -0
- data/lib/gorillib/model/factories.rb +1 -367
- data/lib/gorillib/model/field.rb +40 -18
- data/lib/gorillib/model/fixup.rb +16 -0
- data/lib/gorillib/model/positional_fields.rb +35 -0
- data/lib/gorillib/model/schema_magic.rb +162 -0
- data/lib/gorillib/model/serialization.rb +1 -2
- data/lib/gorillib/model/serialization/csv.rb +59 -0
- data/lib/gorillib/pathname.rb +19 -8
- data/lib/gorillib/some.rb +2 -0
- data/lib/gorillib/string/constantize.rb +17 -10
- data/lib/gorillib/string/inflector.rb +11 -7
- data/lib/gorillib/type/boolean.rb +40 -0
- data/lib/gorillib/type/extended.rb +76 -40
- data/lib/gorillib/type/url.rb +6 -4
- data/lib/gorillib/utils/console.rb +1 -18
- data/lib/gorillib/utils/edge_cases.rb +18 -0
- data/spec/examples/builder/ironfan_spec.rb +5 -10
- data/spec/gorillib/array/compact_blank_spec.rb +36 -21
- data/spec/gorillib/array/simple_statistics_spec.rb +143 -0
- data/spec/gorillib/builder_spec.rb +16 -20
- data/spec/gorillib/collection_spec.rb +131 -35
- data/spec/gorillib/exception/raisers_spec.rb +39 -0
- data/spec/gorillib/hash/deep_compact_spec.rb +3 -3
- data/spec/gorillib/model/{record/defaults_spec.rb → defaults_spec.rb} +5 -1
- data/spec/gorillib/model/factories_spec.rb +335 -0
- data/spec/gorillib/model/{record/overlay_spec.rb → overlay_spec.rb} +0 -0
- data/spec/gorillib/model/serialization_spec.rb +2 -2
- data/spec/gorillib/model_spec.rb +19 -18
- data/spec/gorillib/pathname_spec.rb +7 -7
- data/spec/gorillib/string/truncate_spec.rb +3 -13
- data/spec/gorillib/type/extended_spec.rb +50 -2
- data/spec/gorillib/utils/capture_output_spec.rb +1 -1
- data/spec/spec_helper.rb +10 -7
- data/spec/support/factory_test_helpers.rb +76 -0
- data/spec/support/gorillib_test_helpers.rb +36 -24
- data/spec/support/model_test_helpers.rb +39 -2
- metadata +86 -51
- data/lib/alt/kernel/call_stack.rb +0 -56
- data/lib/gorillib/array/sorted_sample.rb +0 -12
- data/lib/gorillib/builder/field.rb +0 -5
- data/lib/gorillib/collection/has_collection.rb +0 -31
- data/lib/gorillib/collection/list_collection.rb +0 -58
- data/lib/gorillib/exception/confidence.rb +0 -17
- data/lib/gorillib/io/system_helpers.rb +0 -30
- data/lib/gorillib/model/record_schema.rb +0 -9
- data/lib/gorillib/utils/stub_module.rb +0 -33
- data/spec/array/average_spec.rb +0 -24
- data/spec/array/sorted_median_spec.rb +0 -18
- data/spec/array/sorted_percentile_spec.rb +0 -24
- data/spec/array/sorted_sample_spec.rb +0 -28
- data/spec/gorillib/metaprogramming/aliasing_spec.rb +0 -180
- data/spec/gorillib/model/record/factories_spec.rb +0 -335
- data/spec/support/kcode_test_helper.rb +0 -16
data/lib/gorillib/some.rb
CHANGED
@@ -1,28 +1,35 @@
|
|
1
1
|
require 'gorillib/string/inflector'
|
2
2
|
class String
|
3
3
|
|
4
|
-
#
|
5
|
-
# in the string. It raises a NameError when the name is not in CamelCase
|
6
|
-
# or is not initialized. See Gorillib::Inflector.constantize
|
4
|
+
# Find a declared constant with the name specified in the string, or raise.
|
7
5
|
#
|
8
|
-
#
|
6
|
+
# @example
|
9
7
|
# "Module".constantize # => Module
|
10
8
|
# "Class".constantize # => Class
|
11
9
|
# "blargle".constantize # => NameError: wrong constant name blargle
|
10
|
+
#
|
11
|
+
# @raise [NameError] when the name is not in CamelCase or is not initialized.
|
12
|
+
# @return [Module,Class] the specified class
|
13
|
+
# @see Gorillib::Inflector.constantize
|
12
14
|
def constantize
|
13
15
|
Gorillib::Inflector.constantize(self)
|
14
|
-
end
|
16
|
+
end
|
15
17
|
|
16
|
-
#
|
17
|
-
#
|
18
|
-
# or is not
|
18
|
+
# Find a declared constant with the name specified in the string, or return nil.
|
19
|
+
#
|
20
|
+
# @return [Module,Class] the specified class, or nil when the name is not in
|
21
|
+
# CamelCase or is not initialized.
|
19
22
|
#
|
20
|
-
#
|
23
|
+
# @example
|
21
24
|
# "Module".safe_constantize # => Module
|
22
25
|
# "Class".safe_constantize # => Class
|
23
26
|
# "blargle".safe_constantize # => nil
|
27
|
+
#
|
28
|
+
# @see Gorillib::Model::Inflector.safe_constantize
|
29
|
+
# @return [Module,Class] the specified constant,
|
30
|
+
# or nil when the name is not in CamelCase or is not initialized.
|
24
31
|
def safe_constantize
|
25
32
|
Gorillib::Inflector.safe_constantize(self)
|
26
|
-
end
|
33
|
+
end
|
27
34
|
|
28
35
|
end
|
@@ -120,14 +120,16 @@ module Gorillib::Inflector
|
|
120
120
|
Object.module_eval("::#{$1}", __FILE__, __LINE__)
|
121
121
|
end
|
122
122
|
|
123
|
-
# Tries to find a constant with the name specified in the
|
123
|
+
# Tries to find a declared constant with the name specified in the string, or return nil.
|
124
124
|
#
|
125
|
-
#
|
126
|
-
# "
|
125
|
+
# @example
|
126
|
+
# "Module".safe_constantize # => Module
|
127
|
+
# "Class".safe_constantize # => Class
|
127
128
|
#
|
128
|
-
# The name is assumed to be the one of a top-level constant, no matter whether
|
129
|
+
# The `name` is assumed to be the one of a top-level constant, no matter whether
|
129
130
|
# it starts with "::" or not. No lexical context is taken into account:
|
130
131
|
#
|
132
|
+
# @example finds the top-level constant `::C`, not `::M::C`
|
131
133
|
# C = 'outside'
|
132
134
|
# module M
|
133
135
|
# C = 'inside'
|
@@ -135,13 +137,15 @@ module Gorillib::Inflector
|
|
135
137
|
# "C".safe_constantize # => 'outside', same as ::C
|
136
138
|
# end
|
137
139
|
#
|
138
|
-
# nil is returned when the name is not in CamelCase or the constant (or part of it) is
|
139
|
-
# unknown.
|
140
|
-
#
|
140
|
+
# @example nil is returned when the name is not in CamelCase or the constant (or part of it) is unknown.
|
141
141
|
# "blargle".safe_constantize # => nil
|
142
142
|
# "UnknownModule".safe_constantize # => nil
|
143
143
|
# "UnknownModule::Foo::Bar".safe_constantize # => nil
|
144
144
|
#
|
145
|
+
#
|
146
|
+
# @see String.safe_constantize
|
147
|
+
# @return [Module,Class] the specified constant,
|
148
|
+
# or nil when the name is not in CamelCase or is not initialized.
|
145
149
|
def safe_constantize(camel_cased_word)
|
146
150
|
begin
|
147
151
|
constantize(camel_cased_word)
|
@@ -0,0 +1,40 @@
|
|
1
|
+
|
2
|
+
# require 'gorillib/metaprogramming/delegation'
|
3
|
+
#
|
4
|
+
# class ::Boolean < ::Object
|
5
|
+
# attr_accessor :val
|
6
|
+
# def initialize(val=nil)
|
7
|
+
# self.val = val
|
8
|
+
# end
|
9
|
+
#
|
10
|
+
# delegate :!, :to_s, :blank?, :frozen?, :nil?, :present?, :to => :val
|
11
|
+
# delegate :!=, :&, :<=>, :=~, :^, :|, :to => :val
|
12
|
+
#
|
13
|
+
# def inspect()
|
14
|
+
# "<Boolean #{val.inspect}>"
|
15
|
+
# end
|
16
|
+
# def try_dup()
|
17
|
+
# ::Boolean.new(val)
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# def self.true ; self.new(true) ; end
|
21
|
+
# def self.false ; self.new(false) ; end
|
22
|
+
#
|
23
|
+
# def is_a?(klass) val.is_a?(klass) || super ; end
|
24
|
+
# def kind_of?(klass) val.kind_of?(klass) || super ; end
|
25
|
+
# def instance_of?(klass) val.instance_of?(klass) || super ; end
|
26
|
+
#
|
27
|
+
# def !=(other_val) other_val = other_val.val if other_val.is_a?(::Boolean) ; (val != other_val) ; end
|
28
|
+
# def ==(other_val) other_val = other_val.val if other_val.is_a?(::Boolean) ; (val == other_val) ; end
|
29
|
+
# def ===(other_val) other_val = other_val.val if other_val.is_a?(::Boolean) ; (val === other_val) ; end
|
30
|
+
# def <=>(other_val) other_val = other_val.val if other_val.is_a?(::Boolean) ; (val <=> other_val) ; end
|
31
|
+
# def eql?(other_val) other_val = other_val.val if other_val.is_a?(::Boolean) ; (val.eql? other_val) ; end
|
32
|
+
# def equal?(other_val) other_val = other_val.val if other_val.is_a?(::Boolean) ; (val.equal? other_val) ; end
|
33
|
+
#
|
34
|
+
# end
|
35
|
+
|
36
|
+
# Datamapper also defines:
|
37
|
+
#
|
38
|
+
# Apikey BCryptHash Decimal URI UUID Slug CommaSeparatedList Csv IpAddress Json Yaml Enum Flag Discriminator
|
39
|
+
#
|
40
|
+
# maybe someday we will too...
|
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'pathname'
|
2
|
-
require '
|
2
|
+
require 'date'
|
3
|
+
require 'set'
|
4
|
+
require 'gorillib/factories'
|
3
5
|
|
4
6
|
class ::Long < ::Integer ; end
|
5
7
|
class ::Double < ::Float ; end
|
@@ -9,42 +11,76 @@ class ::Guid < ::String ; end
|
|
9
11
|
class ::IpAddress < ::String ; end
|
10
12
|
class ::Hostname < ::String ; end
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
#
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
#
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
14
|
+
class ::EpochTime < ::Integer ; end
|
15
|
+
class ::IntTime < ::EpochTime ; end
|
16
|
+
|
17
|
+
module Gorillib
|
18
|
+
module Factory
|
19
|
+
class GuidFactory < StringFactory ; self.product = ::Guid ; register_factory! ; end
|
20
|
+
class HostnameFactory < StringFactory ; self.product = ::Hostname ; register_factory! ; end
|
21
|
+
class IpAddressFactory < StringFactory ; self.product = ::IpAddress ; register_factory! ; end
|
22
|
+
|
23
|
+
class DateFactory < ConvertingFactory
|
24
|
+
self.product = Date
|
25
|
+
FLAT_DATE_RE = /\A\d{8}Z?\z/
|
26
|
+
register_factory!
|
27
|
+
#
|
28
|
+
def convert(obj)
|
29
|
+
case obj
|
30
|
+
when FLAT_DATE_RE then product.new(obj[0..3].to_i, obj[4..5].to_i, obj[6..7].to_i)
|
31
|
+
when Time then Date.new(obj.year, obj.month, obj.day)
|
32
|
+
when String then Date.parse(obj)
|
33
|
+
else mismatched!(obj)
|
34
|
+
end
|
35
|
+
rescue ArgumentError => err
|
36
|
+
raise if err.is_a?(TypeMismatchError)
|
37
|
+
warn "Cannot parse time #{obj}: #{err}"
|
38
|
+
return nil
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class EpochTimeFactory < ConvertingFactory
|
43
|
+
self.product = Integer
|
44
|
+
def self.typename() :epoch_time ; end
|
45
|
+
register_factory! :epoch_time, EpochTime
|
46
|
+
#
|
47
|
+
def convert(obj)
|
48
|
+
case obj
|
49
|
+
when Numeric then obj.to_f
|
50
|
+
when Time then obj.to_f
|
51
|
+
when /\A\d{14}Z?\z/ then Time.parse(obj)
|
52
|
+
when String then Time.parse_safely(obj).to_f
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class IntTimeFactory < EpochTimeFactory
|
58
|
+
def self.typename() :int_time ; end
|
59
|
+
register_factory! :int_time, IntTime
|
60
|
+
#
|
61
|
+
def convert(obj)
|
62
|
+
result = super
|
63
|
+
result.nil? ? nil : result.to_i
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class Boolean10Factory < BooleanFactory
|
68
|
+
def self.typename() :boolean_10 ; end
|
69
|
+
register_factory! :boolean_10
|
70
|
+
#
|
71
|
+
def convert(obj)
|
72
|
+
case obj.to_s
|
73
|
+
when "0" then false
|
74
|
+
when "1" then true
|
75
|
+
else super
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class SetFactory < EnumerableFactory
|
81
|
+
self.product = Set
|
82
|
+
register_factory!
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
data/lib/gorillib/type/url.rb
CHANGED
@@ -2,8 +2,10 @@ require 'addressable/uri'
|
|
2
2
|
|
3
3
|
class ::Url < Addressable::URI ; end
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
module Gorillib::Factory
|
6
|
+
class UrlFactory < Gorillib::Factory::ConvertingFactory
|
7
|
+
self.product = ::Url
|
8
|
+
def convert(obj) product.parse(obj) ; end
|
9
|
+
register_factory!
|
10
|
+
end
|
9
11
|
end
|
@@ -36,7 +36,7 @@ class ItsATrap < BasicObject
|
|
36
36
|
alias_method :pretty_inspect, :inspect
|
37
37
|
def methods() @obj.methods ; end
|
38
38
|
|
39
|
-
# @
|
39
|
+
# @return the proxied object
|
40
40
|
def __obj__ ; @obj ; end
|
41
41
|
|
42
42
|
# These are defined on BasicObject, delegate them along with the rest
|
@@ -70,23 +70,6 @@ private
|
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
73
|
-
module Test
|
74
|
-
module_function
|
75
|
-
|
76
|
-
def create_class(name, *args, &block)
|
77
|
-
Object.class_eval do
|
78
|
-
remove_const(name) if self.const_defined?(name)
|
79
|
-
const_set(name, Class.new(*args, &block))
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
def example_singleton(name, *args)
|
84
|
-
require 'singleton'
|
85
|
-
create_class(name, *args){ include ::Singleton }
|
86
|
-
end
|
87
|
-
|
88
|
-
end
|
89
|
-
|
90
73
|
class Module
|
91
74
|
|
92
75
|
#
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
module Gorillib
|
3
|
+
module Utils
|
4
|
+
module EdgeCases
|
5
|
+
# Thanks http://www.geertvanderploeg.com/unicode-gen/ !
|
6
|
+
# For more fun, see http://www.tamasoft.co.jp/en/general-info/unicode.html
|
7
|
+
STRINGS = {
|
8
|
+
:unicode_smileys => '٩(-̮̮̃-̃)۶ ٩(●̮̮̃•̃)۶ ٩(͡๏̯͡๏)۶ ٩(-̮̮̃•̃).',
|
9
|
+
:internationalization => 'Intèrnatiònãlïzãtíon',
|
10
|
+
:html_unsafe => 'Testing «Mònkêy Sí Monkè Dü»: 1<2 & 4+1>3, now 20% off!',
|
11
|
+
|
12
|
+
:eastern_arabic_digits => '٠١٢٣٤٥٦٧٨٩',
|
13
|
+
:bengali_digits => '০১২৩৪৫৬৭৮৯',
|
14
|
+
}
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -1,21 +1,16 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
# related libs
|
3
|
-
require 'gorillib/model'
|
4
|
-
require 'gorillib/model/field'
|
5
|
-
require 'gorillib/model/defaults'
|
6
|
-
# libs under test
|
7
|
-
require 'gorillib/builder'
|
8
|
-
require 'gorillib/builder/field'
|
9
|
-
require 'gorillib/string/simple_inflector'
|
10
|
-
# testing helpers
|
11
2
|
|
12
|
-
|
3
|
+
require 'gorillib/builder'
|
13
4
|
|
14
5
|
module Gorillib::Test ; end
|
15
6
|
module Meta::Gorillib::Test ; end
|
16
7
|
|
17
8
|
describe Gorillib::Builder, :model_spec => true do
|
9
|
+
before do
|
10
|
+
require_relative '../../../examples/builder/ironfan.rb'
|
11
|
+
end
|
18
12
|
after(:each){ Gorillib::Test.nuke_constants ; Meta::Gorillib::Test.nuke_constants }
|
13
|
+
|
19
14
|
def example_cluster
|
20
15
|
Gorillib::Test.cluster
|
21
16
|
end
|
@@ -1,37 +1,52 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'gorillib/array/compact_blank'
|
3
3
|
|
4
|
-
describe Array, :simple_spec
|
4
|
+
describe Array, :simple_spec do
|
5
|
+
let(:blankish){ mock('blankish', :blank? => true) }
|
6
|
+
let(:nonblank){ mock('nonblank', :blank? => false) }
|
5
7
|
|
6
8
|
describe '#compact_blank' do
|
7
|
-
it '
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
it 'omits nils, like #compact' do
|
10
|
+
arr = [nil]
|
11
|
+
arr.compact_blank.should == []
|
12
|
+
arr.length.should == 1
|
13
|
+
end
|
14
|
+
it "also omits false, {}, '' and anything else #blank\?" do
|
15
|
+
arr = [nil, false, {}, "", blankish]
|
16
|
+
arr.compact_blank.should == []
|
17
|
+
arr.length.should == 5
|
12
18
|
end
|
13
19
|
|
14
|
-
it '
|
15
|
-
|
16
|
-
|
17
|
-
|
20
|
+
it 'preserves non-blank elements' do
|
21
|
+
arr = [nil, 1, nil, 2]
|
22
|
+
arr.compact_blank.should == [1, 2]
|
23
|
+
arr.length.should == 4
|
24
|
+
arr = [nil, 1, false, 2, {}, ""]
|
25
|
+
arr.compact_blank.should == [1, 2]
|
26
|
+
arr.length.should == 6
|
18
27
|
end
|
19
28
|
end
|
20
29
|
|
21
30
|
describe '#compact_blank!' do
|
22
|
-
it '
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
arr.length.should == 0
|
27
|
-
end
|
31
|
+
it 'removes nils in-place, like #compact!' do
|
32
|
+
arr = [nil]
|
33
|
+
arr.compact_blank!.should == []
|
34
|
+
arr.length.should == 0
|
28
35
|
end
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
end
|
36
|
+
it "removes false, {}, '' and anything else #blank\?" do
|
37
|
+
arr = [nil, false, {}, "", blankish]
|
38
|
+
arr.compact_blank!.should == []
|
39
|
+
arr.length.should == 0
|
34
40
|
end
|
35
41
|
|
42
|
+
it 'preserves non-blank elements' do
|
43
|
+
arr = [nil, 1, nil, 2]
|
44
|
+
arr.compact_blank!.should == [1, 2]
|
45
|
+
arr.length.should == 2
|
46
|
+
arr = [nil, 1, false, 2, {}, ""]
|
47
|
+
arr.compact_blank!.should == [1, 2]
|
48
|
+
arr.length.should == 2
|
49
|
+
end
|
36
50
|
end
|
51
|
+
|
37
52
|
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'gorillib/array/simple_statistics'
|
3
|
+
|
4
|
+
describe Array, :simple_spec do
|
5
|
+
let(:seven_squares){ [ 1, 4, 9, 16, 25, 36, 49] }
|
6
|
+
let(:five_squares ){ [ 1, 4, 16, 36, 49 ] }
|
7
|
+
let(:one_element ){ [ 16 ] }
|
8
|
+
subject{ seven_squares }
|
9
|
+
|
10
|
+
describe '#average' do
|
11
|
+
it('is nil for empty array'){ [].average.should be_nil }
|
12
|
+
it('is the numeric mean') do
|
13
|
+
five_squares.average.should eql 21.2
|
14
|
+
seven_squares.average.should eql 20.0
|
15
|
+
one_element.average.should eql 16.0
|
16
|
+
end
|
17
|
+
it('is is uptyped by its elements') do
|
18
|
+
five_squares.map(&:to_f).average.should eql 21.2
|
19
|
+
[ Complex(1.0,2.0), Complex(3,4), Complex(5) ].average.should eql Complex(3.0,2.0)
|
20
|
+
[ Complex(1,2), Complex(3,4), Complex(5) ].average.should eql (Complex(9,6) / 3.0)
|
21
|
+
end
|
22
|
+
context 'on non-float array element' do
|
23
|
+
it 'raises error' do
|
24
|
+
expect{ [0.0, :b, 1.0].average }.to raise_error(TypeError, /:b can\'t be coerced into Float/)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
context 'with empty' do
|
28
|
+
it 'returns nil' do
|
29
|
+
[].average.should be_nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
context 'given a numerical array' do
|
33
|
+
it 'returns the average of the elements' do
|
34
|
+
(1..10).to_a.average.should == 5.5
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '#at_fraction' do
|
40
|
+
it('is nil for empty array'){ [].at_fraction(0.5).should be_nil }
|
41
|
+
it 'indexes correctly' do
|
42
|
+
seven_squares.at_fraction(0 ).should == 1
|
43
|
+
seven_squares.at_fraction(0.5).should == 16
|
44
|
+
seven_squares.at_fraction(1.0).should == 49
|
45
|
+
five_squares.at_fraction(0.75).should == 36
|
46
|
+
end
|
47
|
+
it 'returns the value the nth of the way along' do
|
48
|
+
(0..6).map{|nth| seven_squares.at_fraction(nth/6.0).should == seven_squares[nth] }
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'raises if the fraction is not a number between 0.0 and 1.0' do
|
52
|
+
expect{ subject.at_fraction(1.0001) }.to raise_error(ArgumentError, /between 0.0 and 1\.0: got 1\.0001/)
|
53
|
+
expect{ subject.at_fraction(-1) }.to raise_error(ArgumentError, /between 0.0 and 1\.0: got -1/)
|
54
|
+
expect{ subject.at_fraction('1.1') }.to raise_error(ArgumentError, /between 0.0 and 1\.0: got \"1.1\"/)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe '#take_nths' do
|
59
|
+
it 'gives elements at 0.5/n, 1.5/n, 2.5/n ... n-0.5/n' do
|
60
|
+
five_squares.take_nths(2).should == [ 4, 36 ]
|
61
|
+
five_squares.take_nths(3).should == [ 4, 16, 36 ]
|
62
|
+
five_squares.take_nths(4).should == [ 4, 16, 36,49]
|
63
|
+
five_squares.take_nths(5).should == [1, 4, 16, 36,49]
|
64
|
+
seven_squares.take_nths(1).should == [ 16 ]
|
65
|
+
seven_squares.take_nths(2).should == [ 9, 36 ]
|
66
|
+
seven_squares.take_nths(3).should == [ 4, 16, 36 ]
|
67
|
+
seven_squares.take_nths(4).should == [ 4, 9, 25,36 ]
|
68
|
+
seven_squares.take_nths(5).should == [ 4, 9,16,25,36 ]
|
69
|
+
seven_squares.take_nths(6).should == [ 4, 9,16,25,36,49]
|
70
|
+
seven_squares.take_nths(99).should == seven_squares
|
71
|
+
seven_squares.take_nths(0).should == []
|
72
|
+
[].take_nths(3).should == []
|
73
|
+
end
|
74
|
+
context 'with empty' do
|
75
|
+
it 'returns an empty array' do
|
76
|
+
[].take_nths(1).should be_empty
|
77
|
+
end
|
78
|
+
end
|
79
|
+
context 'given any array' do
|
80
|
+
it ('returns a sample of the given size as close to evenly ' \
|
81
|
+
'distributed over the array as possible') do
|
82
|
+
nths = (1..100).to_a.take_nths(26)
|
83
|
+
deltas = nths[0..-2].zip(nths[1..-1]).map{|a,b| b-a}
|
84
|
+
deltas.max.should <= 4
|
85
|
+
deltas.min.should >= 3
|
86
|
+
end
|
87
|
+
end
|
88
|
+
context 'given an undersized array' do
|
89
|
+
it 'does not return the same element more than once' do
|
90
|
+
("a".."z").to_a.take_nths(27).should == ("a".."z").to_a
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe '#sorted_median' do
|
96
|
+
it 'takes the halfway-th element' do
|
97
|
+
five_squares.sorted_median.should eql 16
|
98
|
+
seven_squares.sorted_median.should eql 16
|
99
|
+
end
|
100
|
+
context 'with empty' do
|
101
|
+
it 'returns nil' do
|
102
|
+
[].sorted_median.should be_nil
|
103
|
+
end
|
104
|
+
end
|
105
|
+
context 'given any array' do
|
106
|
+
it 'returns the middle element of odd-sized arrays' do
|
107
|
+
("a".."y").to_a.sorted_median.should == "m"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe '#sorted_percentile' do
|
113
|
+
context 'with empty' do
|
114
|
+
it 'returns nil' do
|
115
|
+
[].sorted_percentile(0.0).should be_nil
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
context 'given any array' do
|
120
|
+
it 'returns the element closest to the given percentile' do
|
121
|
+
("a".."y").to_a.sorted_percentile( 0.0).should == "a"
|
122
|
+
("a".."y").to_a.sorted_percentile( 50.0).should == "m"
|
123
|
+
("a".."y").to_a.sorted_percentile(100.0).should == "y"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# (Please do not define behavior for two elements equally close to
|
128
|
+
# a given percentile.)
|
129
|
+
|
130
|
+
it 'takes fractional index at pct/100' do
|
131
|
+
five_squares .sorted_percentile(50).should eql 16
|
132
|
+
seven_squares.sorted_percentile(10).should eql 4
|
133
|
+
seven_squares.sorted_percentile(50).should eql 16
|
134
|
+
seven_squares.sorted_percentile(90).should eql 36
|
135
|
+
seven_squares.sorted_percentile(100).should eql 49
|
136
|
+
end
|
137
|
+
it 'returns nil on empty array' do
|
138
|
+
[].sorted_median.should be nil
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
|
143
|
+
end
|