gorillib 0.4.2 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -0
- data/VERSION +1 -1
- data/gorillib.gemspec +32 -5
- data/lib/gorillib/array/hashify.rb +11 -0
- data/lib/gorillib/base.rb +1 -0
- data/lib/gorillib/data_munging.rb +8 -1
- data/lib/gorillib/exception/raisers.rb +6 -1
- data/lib/gorillib/factories.rb +26 -13
- data/lib/gorillib/model/base.rb +6 -1
- data/lib/gorillib/model/schema_magic.rb +1 -0
- data/lib/gorillib/model/serialization/csv.rb +2 -0
- data/lib/gorillib/model/serialization/json.rb +44 -0
- data/lib/gorillib/model/serialization/lines.rb +30 -0
- data/lib/gorillib/model/serialization/tsv.rb +55 -0
- data/lib/gorillib/pathname/utils.rb +34 -0
- data/lib/gorillib/type/extended.rb +1 -0
- data/lib/gorillib/type/ip_address.rb +153 -0
- data/notes/HOWTO.md +22 -0
- data/notes/bucket.md +155 -0
- data/notes/builder.md +170 -0
- data/notes/collection.md +81 -0
- data/notes/factories.md +86 -0
- data/notes/model-overlay.md +209 -0
- data/notes/model.md +135 -0
- data/notes/structured-data-classes.md +127 -0
- data/spec/gorillib/array/hashify_spec.rb +20 -0
- data/spec/gorillib/builder_spec.rb +2 -2
- data/spec/gorillib/{model/factories_spec.rb → factories_spec.rb} +3 -5
- data/spec/gorillib/model/serialization/tsv_spec.rb +17 -0
- data/spec/gorillib/type/ip_address_spec.rb +143 -0
- metadata +35 -5
@@ -0,0 +1,127 @@
|
|
1
|
+
# gorillib's structured data classes -- Record, Model, Builder and Bucket
|
2
|
+
|
3
|
+
## Overview
|
4
|
+
|
5
|
+
Gorillib provides these general flavors of model:
|
6
|
+
|
7
|
+
* `Gorillib::Record`: **lightweight structured records**. Easily assemble a dynamic data structure that enables both rich behavior and generic manipulation, serialization and transformation. Especially useful when you just need to pull something from JSON, attach some functionality, and get it back on the wire.
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
class Place
|
11
|
+
include Gorillib::Record
|
12
|
+
# fields can be simple...
|
13
|
+
field :name, String
|
14
|
+
field :country_id, String, :doc => 'Country code (2-letter alpha) containing the place'
|
15
|
+
# ... or complext
|
16
|
+
field :geo, GeoCoordinates, :doc => 'geographic location of the place'
|
17
|
+
end
|
18
|
+
|
19
|
+
class GeoCoordinates
|
20
|
+
include Gorillib::Record
|
21
|
+
field :latitude, Float, :doc => 'latitude in decimal degrees; negative numbers are south of the equator'
|
22
|
+
field :longitude, Float, :doc => 'longitude in decimal degrees; negative numbers are west of Greenwich'
|
23
|
+
end
|
24
|
+
|
25
|
+
# It's simple to instantiate complex nested data structures
|
26
|
+
lunch_spot = Place.receive({ :name => "Torchy's Tacos", :country_id => "us",
|
27
|
+
:geo => { :latitude => "30.295", :longitude => "-97.745" }})
|
28
|
+
```
|
29
|
+
|
30
|
+
* `Gorillib::Model`: **rich structured models** offering predictable magic with a disciplined footprint. Comparable to ActiveRecord or Datamapper, but for a world dominated by JSON+HTTP, not relational databases
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
class GeoCoordinates
|
34
|
+
include Gorillib::Model
|
35
|
+
field :latitude, Float, :doc => 'latitude in decimal degrees; negative numbers are south of the equator', :validates => { :numericality => { :>= => -90, :<= => 90 } }
|
36
|
+
field :longitude, Float, :doc => 'longitude in decimal degrees; negative numbers are west of Greenwich', :validates => { :numericality => { :>= => -180, :<= => 180 } }
|
37
|
+
end
|
38
|
+
position = GeoCoordinates.from_tuple(30.295, -97.745)
|
39
|
+
# A Gorillib::Model obeys the ActiveModel contract
|
40
|
+
GeoCoordinates.model_name.human # => 'Geo coordinates'
|
41
|
+
```
|
42
|
+
|
43
|
+
* `Gorillib::Builder`: **foundation models for elegant ruby DSLs** (Domain-Specific Languages). Relaxes ruby syntax to enable highly-readable specification of complex behavior.
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
workflow(:bake_pie) do
|
47
|
+
step :make_crust
|
48
|
+
step :add_filling
|
49
|
+
step :bake
|
50
|
+
step :cool
|
51
|
+
end
|
52
|
+
```
|
53
|
+
|
54
|
+
* `Gorillib::Bucket` (?name?): **record-style access to freeform hashes**. Provide a disciplined interface on top of arbitrarily-structured data. Used by [[Configliere]] and others.
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
# pre-defining a field gives you special powers...
|
58
|
+
Settings.define :port, Integer, :doc => 'API server port number', :default => 80
|
59
|
+
# but you can still store or read anything you'd like...
|
60
|
+
Settings[:shout] = "SAN DIMAS HIGH SCHOOL FOOTBALL RULES"
|
61
|
+
# and treat the object as a hash when you'd like to
|
62
|
+
conn = Connections.open(Settings.merge(user_overrides))
|
63
|
+
```
|
64
|
+
|
65
|
+
## Decisions
|
66
|
+
|
67
|
+
* **initializer** - *does not* inject an initializer; if you want one, do `alias_method :initialize, :receive!`
|
68
|
+
* **frills** --
|
69
|
+
- *does inject*: `inspect` on the class, `inspect`, `to_s` on the instance
|
70
|
+
- *does inject*: accessors (`foo`, `foo=`) for each field.
|
71
|
+
- *does inject*: `==` on the instance
|
72
|
+
- *does not define*: `schema`, `initialize`
|
73
|
+
* **field defaults** - evaluated on first read, at which point its value is fixed on the record.
|
74
|
+
|
75
|
+
* **define_metamodel_record** -- visibility=false does not remove an existing method from the metamodel
|
76
|
+
|
77
|
+
* ?? **hash vs mash** -- does `attributes` return a mash or hash?
|
78
|
+
* are these basic functionality:
|
79
|
+
- **extra_attributes** -- ??
|
80
|
+
- **default** -- ??
|
81
|
+
|
82
|
+
* Record:
|
83
|
+
- class methods -- `field`, `fields`, `field_names`, `has_field?`, `metamodel`, `receive`, `inspect`
|
84
|
+
- instance methods -- `read_attribute`, `write_attribute`, `unset_attribute`, `attribute_set?`, `attributes`, `receive!`, `update`, `inspect`, `to_s`, `==`
|
85
|
+
- with each attribute -- `receive_foo`, `foo=`, `foo`
|
86
|
+
|
87
|
+
* Builder:
|
88
|
+
- defining classes before they're used
|
89
|
+
|
90
|
+
|
91
|
+
## Features
|
92
|
+
|
93
|
+
### `Record`
|
94
|
+
|
95
|
+
* `Record::Ordered` -- sort order on fields (and thus record)
|
96
|
+
* `Record::FieldAliasing` -- aliases for fields and receivers
|
97
|
+
* `Record::Defaults` -- default values
|
98
|
+
* `Record::Schema` -- icss schema
|
99
|
+
* `Record::HashAccessors` -- adds `[]`, `[]=`, `delete`, `keys`, `#has_key?`, `to_hash`, and `update`. This allows it to be `hashlike`, but you must include that explicitly.
|
100
|
+
* `Record::Hashlike` -- mixes in `Record::HashAccessors` and `Gorillib::Hashlike`, making it behave in almost every respect like a hash. Use this when you want something that will *behave* like a hash but *be* a record. If you want something to *be* a hash but *behave* like a record, use the `Gorillib::MashRecord`
|
101
|
+
|
102
|
+
### `Builder`
|
103
|
+
|
104
|
+
* `Builder::GetsetField` --
|
105
|
+
|
106
|
+
### `HashRecord`
|
107
|
+
|
108
|
+
### `Model`
|
109
|
+
|
110
|
+
* `Model::Naming`
|
111
|
+
* `Model::Conversion` --
|
112
|
+
|
113
|
+
### active_model / active_model_lite
|
114
|
+
|
115
|
+
From `active_model` or `active_model_lite`:
|
116
|
+
|
117
|
+
* `Model::Callbacks` --
|
118
|
+
* `Model::Dirty` --
|
119
|
+
* `Model::Serialization` --
|
120
|
+
* `Model::Validations` -- implies `Model::Errors`, `Model::Callbacks`
|
121
|
+
|
122
|
+
|
123
|
+
## Why, in a world with ActiveRecord, Datamapper, Hashie, Struct, ..., do we need yet another damn model framework?
|
124
|
+
|
125
|
+
ActiveRecord and Datamapper excel in a world where data (and truth) live in the database. ActiveRecord sets the standard for elegant magic, but is fairly heavyweight (I don't want to include a full XML serialization suite just so I can validate records). This often means it's overkill for the myriad flyweight scripts, Goliath apps, and such that we deploy. Datamapper does a remarkable job of delivering power while still being light on its toes, but ultimately is too tightly bound to an ORM view of the world. Hashie, Structs and OStructs behave as both hashes and records. In my experience, this interface is too generous -- their use leads to mealymouthed code.
|
126
|
+
|
127
|
+
More importantly, our data spends most of its time on the wire or being handled as an opaque blob of data; a good amount of time being handled as a generic bundle of properties; and (though most important) a relatively small amount of time as an active, assertive object. So type conversion and validation are fundamental actions, but shouldn't crud up my critical path or be required. Models should offer predictable and disciplined features, but be accessable as generic bags of facts.
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'gorillib/array/hashify'
|
3
|
+
|
4
|
+
describe Array, :simple_spec, :only do
|
5
|
+
|
6
|
+
describe '#hashify' do
|
7
|
+
it 'returns a hash pairing elements with value from block' do
|
8
|
+
[1,2,3].hashify{|x| x * x }.should == { 1 => 1, 2 => 4, 3 => 9 }
|
9
|
+
[1,2,3].hashify{|x| x > 2 ? nil : x }.should == { 1 => 1, 2 => 2, 3 => nil }
|
10
|
+
end
|
11
|
+
it "returns an empty hash on an empty array" do
|
12
|
+
[].hashify{}.should == {}
|
13
|
+
end
|
14
|
+
it "fails if no block given" do
|
15
|
+
expect{ [1,2,3].hashify }.to raise_error(ArgumentError)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -17,8 +17,8 @@ describe Gorillib::Builder, :model_spec => true, :builder_spec => true do
|
|
17
17
|
context 'examples:' do
|
18
18
|
let(:subject_class ){ car_class }
|
19
19
|
it 'type-converts values' do
|
20
|
-
obj = subject_class.receive(
|
21
|
-
obj.attributes.should == {
|
20
|
+
obj = subject_class.receive( :name => 'wildcat', :make_model => 'Buick Wildcat', :year => "1968", :doors => "2" )
|
21
|
+
obj.attributes.should == { :name => :wildcat, :make_model => 'Buick Wildcat', :year => 1968, :doors => 2, :engine => nil }
|
22
22
|
end
|
23
23
|
it 'handles nested structures' do
|
24
24
|
obj = subject_class.receive(
|
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
|
2
|
+
require 'support/factory_test_helpers'
|
3
3
|
|
4
4
|
require 'gorillib/object/blank'
|
5
5
|
require 'gorillib/object/try_dup'
|
@@ -8,11 +8,9 @@ require 'gorillib/metaprogramming/class_attribute'
|
|
8
8
|
require 'gorillib/string/inflector'
|
9
9
|
|
10
10
|
require 'gorillib/collection'
|
11
|
-
require 'gorillib/
|
11
|
+
require 'gorillib/factories'
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
describe '', :model_spec, :factory_spec, :only do
|
13
|
+
describe '', :model_spec, :factory_spec do
|
16
14
|
|
17
15
|
describe Gorillib::Factory do
|
18
16
|
describe 'Factory()' do
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'support/model_test_helpers'
|
3
|
+
|
4
|
+
require 'multi_json'
|
5
|
+
#
|
6
|
+
require 'gorillib/model'
|
7
|
+
require 'gorillib/builder'
|
8
|
+
require 'gorillib/model/serialization/tsv'
|
9
|
+
|
10
|
+
describe Gorillib::Model, :model_spec, :builder_spec do
|
11
|
+
|
12
|
+
context ".load_tsv" do
|
13
|
+
# it "respects blank characters at end of line, so '1\\t2\\t\\t\\t becomes [\"1\",\"2\",\"\",\"\",\"\"]" do
|
14
|
+
# # make sure
|
15
|
+
# end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'support/factory_test_helpers'
|
3
|
+
require 'gorillib/object/blank'
|
4
|
+
#
|
5
|
+
require 'gorillib/type/ip_address'
|
6
|
+
|
7
|
+
shared_examples_for(:ip_addresslike) do
|
8
|
+
|
9
|
+
its(:dotted){ should == '1.2.3.4' }
|
10
|
+
its(:quads){ should == [1, 2, 3, 4] }
|
11
|
+
its(:packed){ should == packed_1234 }
|
12
|
+
|
13
|
+
context '.from_packed' do
|
14
|
+
subject{ described_class.from_packed(packed_1234) }
|
15
|
+
it{ should be_a(described_class) }
|
16
|
+
its(:dotted){ should == '1.2.3.4' }
|
17
|
+
end
|
18
|
+
|
19
|
+
context '#bitness_min' do
|
20
|
+
it('is unchanged for /32'){ subject.bitness_min(32).should == subject.packed }
|
21
|
+
{ 0 => 0, # '0.0.0.0'
|
22
|
+
6 => 0, # '0.0.0.0'
|
23
|
+
8 => 0x01000000, # '1.0.0.0',
|
24
|
+
30 => 0x01020304, # '1.2.3.4',
|
25
|
+
}.each do |bitness, result|
|
26
|
+
it("returns #{result} for #{bitness}"){ subject.bitness_min(bitness).should == result }
|
27
|
+
end
|
28
|
+
it 'raises an error if bitness is out of range' do
|
29
|
+
expect{ subject.bitness_min(33) }.to raise_error(ArgumentError, /only 32 bits.*33/)
|
30
|
+
expect{ subject.bitness_min(-1) }.to raise_error(ArgumentError, /only 32 bits.*-1/)
|
31
|
+
expect{ subject.bitness_min('bob') }.to raise_error(ArgumentError, /only 32 bits.*bob/)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context '#bitness_max' do
|
36
|
+
it 'returns an integer' do
|
37
|
+
subject.bitness_max(24).should equal(16909311)
|
38
|
+
end
|
39
|
+
it('is unchanged for /32' ){ subject.bitness_max(32).should == subject.packed }
|
40
|
+
{ 0 => 0xFFFFFFFF, # '255.255.255.255'
|
41
|
+
6 => 0x03FFFFFF, # '3.255.255.255'
|
42
|
+
8 => 0x01FFFFFF, # '1.255.255.255'
|
43
|
+
31 => 0x01020305, # '1.2.3.5'
|
44
|
+
}.each do |bitness, result|
|
45
|
+
it("returns #{result} for #{bitness}"){ subject.bitness_max(bitness).should == result }
|
46
|
+
end
|
47
|
+
it 'raises an error if bitness is out of range' do
|
48
|
+
expect{ subject.bitness_max(33) }.to raise_error(ArgumentError, /only 32 bits.*33/)
|
49
|
+
expect{ subject.bitness_max(-1) }.to raise_error(ArgumentError, /only 32 bits.*-1/)
|
50
|
+
expect{ subject.bitness_max('bob') }.to raise_error(ArgumentError, /only 32 bits.*bob/)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe ::IpAddress do
|
56
|
+
let(:packed_1234){ 16909060 }
|
57
|
+
let(:dotted_1234){ '1.2.3.4' }
|
58
|
+
subject{ described_class.new('1.2.3.4') }
|
59
|
+
|
60
|
+
it_should_behave_like(:ip_addresslike)
|
61
|
+
|
62
|
+
its(:to_i){ should equal(packed_1234) }
|
63
|
+
it{ expect{ subject.to_int }.to raise_error(NoMethodError, /undefined method.*\`to_int\'/) }
|
64
|
+
end
|
65
|
+
|
66
|
+
describe ::IpNumeric do
|
67
|
+
let(:packed_1234){ 16909060 }
|
68
|
+
let(:dotted_1234){ '1.2.3.4' }
|
69
|
+
subject{ described_class.new(packed_1234) }
|
70
|
+
|
71
|
+
it_should_behave_like(:ip_addresslike)
|
72
|
+
|
73
|
+
context '.from_dotted' do
|
74
|
+
subject{ described_class.from_dotted(dotted_1234) }
|
75
|
+
it('memoizes #dotted') do
|
76
|
+
val = subject.instance_variable_get('@dotted')
|
77
|
+
val.should == '1.2.3.4'
|
78
|
+
val.should be_frozen
|
79
|
+
end
|
80
|
+
it('memoizes #quads') do
|
81
|
+
val = subject.instance_variable_get('@quads')
|
82
|
+
val.should == [1,2,3,4]
|
83
|
+
val.should be_frozen
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
describe ::IpRange do
|
91
|
+
let(:beg_1234){ 16909060 }
|
92
|
+
let(:end_1234){ 16909384 }
|
93
|
+
subject{ described_class.new(beg_1234 .. end_1234) }
|
94
|
+
|
95
|
+
its(:min){ should == beg_1234 }
|
96
|
+
its(:max){ should == end_1234 }
|
97
|
+
its(:min){ should be_a(IpNumeric) }
|
98
|
+
its(:max){ should be_a(IpNumeric) }
|
99
|
+
|
100
|
+
context 'bitness_blocks' do
|
101
|
+
it 'emits nothing if empty' do
|
102
|
+
described_class.new(50, 49).bitness_blocks(24).should == []
|
103
|
+
end
|
104
|
+
it 'emits only one block if min and max are in same bitness block' do
|
105
|
+
described_class.new(40, 80).bitness_blocks(24).should == [ [40, 80] ]
|
106
|
+
end
|
107
|
+
it 'emits only one block if min and max are the same' do
|
108
|
+
described_class.new(40, 40).bitness_blocks(24).should == [ [40, 40] ]
|
109
|
+
end
|
110
|
+
it 'emits two short blocks if min and max are in neighboring blocks' do
|
111
|
+
described_class.new(40, 260).bitness_blocks(24).should == [ [40, 255], [256, 260] ]
|
112
|
+
end
|
113
|
+
it 'emits intermediate blocks if min and max are far apart' do
|
114
|
+
described_class.new(40, 520).bitness_blocks(24).should == [ [40, 255], [256, 511], [512, 520] ]
|
115
|
+
end
|
116
|
+
|
117
|
+
{
|
118
|
+
[ '255.255.255.255', '255.255.255.255', 0 ] => [ [0xFFFFFFFF, 0xFFFFFFFF] ],
|
119
|
+
[ '255.255.255.255', '255.255.255.255', 24 ] => [ [0xFFFFFFFF, 0xFFFFFFFF] ],
|
120
|
+
[ '255.255.255.255', '255.255.255.255', 32 ] => [ [0xFFFFFFFF, 0xFFFFFFFF] ],
|
121
|
+
[ '255.255.254.1', '255.255.255.255', 0 ] => [ [0xFFFFFe01, 0xFFFFFFFF] ],
|
122
|
+
[ '255.255.254.1', '255.255.255.255', 24 ] => [ [0xFFFFFe01, 0xFFFFFeFF], [0xFFFFFF00, 0xFFFFFFFF] ],
|
123
|
+
[ '255.255.253.1', '255.255.255.7', 24 ] => [ [0xFFFFFd01, 0xFFFFFdFF], [0xFFFFFe00, 0xFFFFFeFF], [0xFFFFFF00, 0xFFFFFF07] ],
|
124
|
+
[ '0.0.0.0', '0.0.0.0', 24 ] => [ [0x0, 0x0], ],
|
125
|
+
[ '0.0.0.255', '0.0.1.0', 24 ] => [ [0xFF, 0xFF], [0x100, 0x100] ],
|
126
|
+
[ '0.0.0.7', '0.0.0.10', 31 ] => [ [0x7, 0x7], [0x8, 0x9], [0xa, 0xa], ],
|
127
|
+
[ '0.0.0.7', '0.0.0.11', 31 ] => [ [0x7, 0x7], [0x8, 0x9], [0xa, 0xb], ],
|
128
|
+
[ '0.0.0.0', '0.0.0.0', 24 ] => [ [0x0, 0x0], ],
|
129
|
+
[ '0.0.1.7', '0.0.1.255', 24 ] => [ [0x107, 0x1FF], ],
|
130
|
+
[ '0.0.1.7', '0.0.2.7', 24 ] => [ [0x107, 0x1FF], [0x200, 0x207] ],
|
131
|
+
[ '0.0.1.7', '0.0.3.7', 24 ] => [ [0x107, 0x1FF], [0x200, 0x2FF], [0x300, 0x307] ],
|
132
|
+
}.each do |(beg_ip, end_ip, bitness), blocks|
|
133
|
+
it "/#{bitness}-bit blocks of #{beg_ip}..#{end_ip} are #{blocks}" do
|
134
|
+
beg_ip = IpNumeric.from_dotted(beg_ip)
|
135
|
+
end_ip = IpNumeric.from_dotted(end_ip)
|
136
|
+
subject = IpRange.new(beg_ip .. end_ip)
|
137
|
+
subject.bitness_blocks(bitness).should == blocks
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: gorillib
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.
|
5
|
+
version: 0.5.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Infochimps
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2012-
|
13
|
+
date: 2012-10-22 00:00:00 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: multi_json
|
@@ -118,8 +118,18 @@ executables: []
|
|
118
118
|
extensions: []
|
119
119
|
|
120
120
|
extra_rdoc_files:
|
121
|
+
- CHANGELOG.md
|
121
122
|
- LICENSE.md
|
122
123
|
- README.md
|
124
|
+
- TODO.md
|
125
|
+
- notes/HOWTO.md
|
126
|
+
- notes/bucket.md
|
127
|
+
- notes/builder.md
|
128
|
+
- notes/collection.md
|
129
|
+
- notes/factories.md
|
130
|
+
- notes/model-overlay.md
|
131
|
+
- notes/model.md
|
132
|
+
- notes/structured-data-classes.md
|
123
133
|
files:
|
124
134
|
- .gitignore
|
125
135
|
- .rspec
|
@@ -141,6 +151,7 @@ files:
|
|
141
151
|
- lib/gorillib/array/compact_blank.rb
|
142
152
|
- lib/gorillib/array/deep_compact.rb
|
143
153
|
- lib/gorillib/array/extract_options.rb
|
154
|
+
- lib/gorillib/array/hashify.rb
|
144
155
|
- lib/gorillib/array/simple_statistics.rb
|
145
156
|
- lib/gorillib/array/wrap.rb
|
146
157
|
- lib/gorillib/base.rb
|
@@ -203,12 +214,16 @@ files:
|
|
203
214
|
- lib/gorillib/model/schema_magic.rb
|
204
215
|
- lib/gorillib/model/serialization.rb
|
205
216
|
- lib/gorillib/model/serialization/csv.rb
|
217
|
+
- lib/gorillib/model/serialization/json.rb
|
218
|
+
- lib/gorillib/model/serialization/lines.rb
|
219
|
+
- lib/gorillib/model/serialization/tsv.rb
|
206
220
|
- lib/gorillib/model/validate.rb
|
207
221
|
- lib/gorillib/numeric/clamp.rb
|
208
222
|
- lib/gorillib/object/blank.rb
|
209
223
|
- lib/gorillib/object/try.rb
|
210
224
|
- lib/gorillib/object/try_dup.rb
|
211
225
|
- lib/gorillib/pathname.rb
|
226
|
+
- lib/gorillib/pathname/utils.rb
|
212
227
|
- lib/gorillib/serialization/to_wire.rb
|
213
228
|
- lib/gorillib/some.rb
|
214
229
|
- lib/gorillib/string/constantize.rb
|
@@ -219,16 +234,26 @@ files:
|
|
219
234
|
- lib/gorillib/string/truncate.rb
|
220
235
|
- lib/gorillib/type/boolean.rb
|
221
236
|
- lib/gorillib/type/extended.rb
|
237
|
+
- lib/gorillib/type/ip_address.rb
|
222
238
|
- lib/gorillib/type/url.rb
|
223
239
|
- lib/gorillib/utils/capture_output.rb
|
224
240
|
- lib/gorillib/utils/console.rb
|
225
241
|
- lib/gorillib/utils/edge_cases.rb
|
226
242
|
- lib/gorillib/utils/nuke_constants.rb
|
243
|
+
- notes/HOWTO.md
|
244
|
+
- notes/bucket.md
|
245
|
+
- notes/builder.md
|
246
|
+
- notes/collection.md
|
247
|
+
- notes/factories.md
|
248
|
+
- notes/model-overlay.md
|
249
|
+
- notes/model.md
|
250
|
+
- notes/structured-data-classes.md
|
227
251
|
- spec/examples/builder/ironfan_spec.rb
|
228
252
|
- spec/extlib/hash_spec.rb
|
229
253
|
- spec/extlib/mash_spec.rb
|
230
254
|
- spec/gorillib/array/compact_blank_spec.rb
|
231
255
|
- spec/gorillib/array/extract_options_spec.rb
|
256
|
+
- spec/gorillib/array/hashify_spec.rb
|
232
257
|
- spec/gorillib/array/simple_statistics_spec.rb
|
233
258
|
- spec/gorillib/builder_spec.rb
|
234
259
|
- spec/gorillib/collection_spec.rb
|
@@ -237,6 +262,7 @@ files:
|
|
237
262
|
- spec/gorillib/datetime/to_flat_spec.rb
|
238
263
|
- spec/gorillib/enumerable/sum_spec.rb
|
239
264
|
- spec/gorillib/exception/raisers_spec.rb
|
265
|
+
- spec/gorillib/factories_spec.rb
|
240
266
|
- spec/gorillib/hash/compact_spec.rb
|
241
267
|
- spec/gorillib/hash/deep_compact_spec.rb
|
242
268
|
- spec/gorillib/hash/deep_merge_spec.rb
|
@@ -254,9 +280,9 @@ files:
|
|
254
280
|
- spec/gorillib/metaprogramming/delegation_spec.rb
|
255
281
|
- spec/gorillib/metaprogramming/singleton_class_spec.rb
|
256
282
|
- spec/gorillib/model/defaults_spec.rb
|
257
|
-
- spec/gorillib/model/factories_spec.rb
|
258
283
|
- spec/gorillib/model/lint_spec.rb
|
259
284
|
- spec/gorillib/model/overlay_spec.rb
|
285
|
+
- spec/gorillib/model/serialization/tsv_spec.rb
|
260
286
|
- spec/gorillib/model/serialization_spec.rb
|
261
287
|
- spec/gorillib/model_spec.rb
|
262
288
|
- spec/gorillib/numeric/clamp_spec.rb
|
@@ -270,6 +296,7 @@ files:
|
|
270
296
|
- spec/gorillib/string/inflector_test_cases.rb
|
271
297
|
- spec/gorillib/string/truncate_spec.rb
|
272
298
|
- spec/gorillib/type/extended_spec.rb
|
299
|
+
- spec/gorillib/type/ip_address_spec.rb
|
273
300
|
- spec/gorillib/utils/capture_output_spec.rb
|
274
301
|
- spec/spec_helper.rb
|
275
302
|
- spec/support/factory_test_helpers.rb
|
@@ -297,7 +324,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
297
324
|
requirements:
|
298
325
|
- - ">="
|
299
326
|
- !ruby/object:Gem::Version
|
300
|
-
hash:
|
327
|
+
hash: 4018535107500327818
|
301
328
|
segments:
|
302
329
|
- 0
|
303
330
|
version: "0"
|
@@ -345,6 +372,7 @@ test_files:
|
|
345
372
|
- spec/gorillib/utils/capture_output_spec.rb
|
346
373
|
- spec/gorillib/collection_spec.rb
|
347
374
|
- spec/gorillib/type/extended_spec.rb
|
375
|
+
- spec/gorillib/type/ip_address_spec.rb
|
348
376
|
- spec/gorillib/hash/zip_spec.rb
|
349
377
|
- spec/gorillib/hash/reverse_merge_spec.rb
|
350
378
|
- spec/gorillib/hash/slice_spec.rb
|
@@ -359,11 +387,12 @@ test_files:
|
|
359
387
|
- spec/gorillib/hashlike/hashlike_via_accessors_spec.rb
|
360
388
|
- spec/gorillib/hashlike/behave_same_as_hash_spec.rb
|
361
389
|
- spec/gorillib/configurable_spec.rb
|
390
|
+
- spec/gorillib/factories_spec.rb
|
391
|
+
- spec/gorillib/model/serialization/tsv_spec.rb
|
362
392
|
- spec/gorillib/model/lint_spec.rb
|
363
393
|
- spec/gorillib/model/defaults_spec.rb
|
364
394
|
- spec/gorillib/model/serialization_spec.rb
|
365
395
|
- spec/gorillib/model/overlay_spec.rb
|
366
|
-
- spec/gorillib/model/factories_spec.rb
|
367
396
|
- spec/gorillib/pathname_spec.rb
|
368
397
|
- spec/gorillib/enumerable/sum_spec.rb
|
369
398
|
- spec/gorillib/object/try_spec.rb
|
@@ -372,6 +401,7 @@ test_files:
|
|
372
401
|
- spec/gorillib/array/compact_blank_spec.rb
|
373
402
|
- spec/gorillib/array/simple_statistics_spec.rb
|
374
403
|
- spec/gorillib/array/extract_options_spec.rb
|
404
|
+
- spec/gorillib/array/hashify_spec.rb
|
375
405
|
- spec/gorillib/logger/log_spec.rb
|
376
406
|
- spec/spec_helper.rb
|
377
407
|
- spec/examples/builder/ironfan_spec.rb
|