gorillib 0.4.1pre → 0.4.2pre
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.
- 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
|