gorillib 0.4.2 → 0.5.0
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/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
data/Rakefile
CHANGED
@@ -42,6 +42,7 @@ Jeweler::Tasks.new do |gem|
|
|
42
42
|
reject{|f| File.directory?(f) }.
|
43
43
|
reject{|f| ignores.any?{|i| File.fnmatch(i, f) || File.fnmatch(i+'/**/*', f) || File.fnmatch(i+'/*', f) } }
|
44
44
|
gem.test_files = gem.files.grep(/^spec\//)
|
45
|
+
gem.extra_rdoc_files = [gem.files.grep(/^notes\//), gem.files.grep(/\.md$/)].flatten.uniq
|
45
46
|
gem.require_paths = ['lib']
|
46
47
|
end
|
47
48
|
Jeweler::RubygemsDotOrgTasks.new
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.5.0
|
data/gorillib.gemspec
CHANGED
@@ -5,16 +5,26 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "gorillib"
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.5.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Infochimps"]
|
12
|
-
s.date = "2012-
|
12
|
+
s.date = "2012-10-22"
|
13
13
|
s.description = "Gorillib: infochimps lightweight subset of ruby convenience methods"
|
14
14
|
s.email = "coders@infochimps.org"
|
15
15
|
s.extra_rdoc_files = [
|
16
|
+
"CHANGELOG.md",
|
16
17
|
"LICENSE.md",
|
17
|
-
"README.md"
|
18
|
+
"README.md",
|
19
|
+
"TODO.md",
|
20
|
+
"notes/HOWTO.md",
|
21
|
+
"notes/bucket.md",
|
22
|
+
"notes/builder.md",
|
23
|
+
"notes/collection.md",
|
24
|
+
"notes/factories.md",
|
25
|
+
"notes/model-overlay.md",
|
26
|
+
"notes/model.md",
|
27
|
+
"notes/structured-data-classes.md"
|
18
28
|
]
|
19
29
|
s.files = [
|
20
30
|
".gitignore",
|
@@ -37,6 +47,7 @@ Gem::Specification.new do |s|
|
|
37
47
|
"lib/gorillib/array/compact_blank.rb",
|
38
48
|
"lib/gorillib/array/deep_compact.rb",
|
39
49
|
"lib/gorillib/array/extract_options.rb",
|
50
|
+
"lib/gorillib/array/hashify.rb",
|
40
51
|
"lib/gorillib/array/simple_statistics.rb",
|
41
52
|
"lib/gorillib/array/wrap.rb",
|
42
53
|
"lib/gorillib/base.rb",
|
@@ -99,12 +110,16 @@ Gem::Specification.new do |s|
|
|
99
110
|
"lib/gorillib/model/schema_magic.rb",
|
100
111
|
"lib/gorillib/model/serialization.rb",
|
101
112
|
"lib/gorillib/model/serialization/csv.rb",
|
113
|
+
"lib/gorillib/model/serialization/json.rb",
|
114
|
+
"lib/gorillib/model/serialization/lines.rb",
|
115
|
+
"lib/gorillib/model/serialization/tsv.rb",
|
102
116
|
"lib/gorillib/model/validate.rb",
|
103
117
|
"lib/gorillib/numeric/clamp.rb",
|
104
118
|
"lib/gorillib/object/blank.rb",
|
105
119
|
"lib/gorillib/object/try.rb",
|
106
120
|
"lib/gorillib/object/try_dup.rb",
|
107
121
|
"lib/gorillib/pathname.rb",
|
122
|
+
"lib/gorillib/pathname/utils.rb",
|
108
123
|
"lib/gorillib/serialization/to_wire.rb",
|
109
124
|
"lib/gorillib/some.rb",
|
110
125
|
"lib/gorillib/string/constantize.rb",
|
@@ -115,16 +130,26 @@ Gem::Specification.new do |s|
|
|
115
130
|
"lib/gorillib/string/truncate.rb",
|
116
131
|
"lib/gorillib/type/boolean.rb",
|
117
132
|
"lib/gorillib/type/extended.rb",
|
133
|
+
"lib/gorillib/type/ip_address.rb",
|
118
134
|
"lib/gorillib/type/url.rb",
|
119
135
|
"lib/gorillib/utils/capture_output.rb",
|
120
136
|
"lib/gorillib/utils/console.rb",
|
121
137
|
"lib/gorillib/utils/edge_cases.rb",
|
122
138
|
"lib/gorillib/utils/nuke_constants.rb",
|
139
|
+
"notes/HOWTO.md",
|
140
|
+
"notes/bucket.md",
|
141
|
+
"notes/builder.md",
|
142
|
+
"notes/collection.md",
|
143
|
+
"notes/factories.md",
|
144
|
+
"notes/model-overlay.md",
|
145
|
+
"notes/model.md",
|
146
|
+
"notes/structured-data-classes.md",
|
123
147
|
"spec/examples/builder/ironfan_spec.rb",
|
124
148
|
"spec/extlib/hash_spec.rb",
|
125
149
|
"spec/extlib/mash_spec.rb",
|
126
150
|
"spec/gorillib/array/compact_blank_spec.rb",
|
127
151
|
"spec/gorillib/array/extract_options_spec.rb",
|
152
|
+
"spec/gorillib/array/hashify_spec.rb",
|
128
153
|
"spec/gorillib/array/simple_statistics_spec.rb",
|
129
154
|
"spec/gorillib/builder_spec.rb",
|
130
155
|
"spec/gorillib/collection_spec.rb",
|
@@ -133,6 +158,7 @@ Gem::Specification.new do |s|
|
|
133
158
|
"spec/gorillib/datetime/to_flat_spec.rb",
|
134
159
|
"spec/gorillib/enumerable/sum_spec.rb",
|
135
160
|
"spec/gorillib/exception/raisers_spec.rb",
|
161
|
+
"spec/gorillib/factories_spec.rb",
|
136
162
|
"spec/gorillib/hash/compact_spec.rb",
|
137
163
|
"spec/gorillib/hash/deep_compact_spec.rb",
|
138
164
|
"spec/gorillib/hash/deep_merge_spec.rb",
|
@@ -150,9 +176,9 @@ Gem::Specification.new do |s|
|
|
150
176
|
"spec/gorillib/metaprogramming/delegation_spec.rb",
|
151
177
|
"spec/gorillib/metaprogramming/singleton_class_spec.rb",
|
152
178
|
"spec/gorillib/model/defaults_spec.rb",
|
153
|
-
"spec/gorillib/model/factories_spec.rb",
|
154
179
|
"spec/gorillib/model/lint_spec.rb",
|
155
180
|
"spec/gorillib/model/overlay_spec.rb",
|
181
|
+
"spec/gorillib/model/serialization/tsv_spec.rb",
|
156
182
|
"spec/gorillib/model/serialization_spec.rb",
|
157
183
|
"spec/gorillib/model_spec.rb",
|
158
184
|
"spec/gorillib/numeric/clamp_spec.rb",
|
@@ -166,6 +192,7 @@ Gem::Specification.new do |s|
|
|
166
192
|
"spec/gorillib/string/inflector_test_cases.rb",
|
167
193
|
"spec/gorillib/string/truncate_spec.rb",
|
168
194
|
"spec/gorillib/type/extended_spec.rb",
|
195
|
+
"spec/gorillib/type/ip_address_spec.rb",
|
169
196
|
"spec/gorillib/utils/capture_output_spec.rb",
|
170
197
|
"spec/spec_helper.rb",
|
171
198
|
"spec/support/factory_test_helpers.rb",
|
@@ -186,7 +213,7 @@ Gem::Specification.new do |s|
|
|
186
213
|
s.require_paths = ["lib"]
|
187
214
|
s.rubygems_version = "1.8.24"
|
188
215
|
s.summary = "include only what you need. No dependencies, no creep"
|
189
|
-
s.test_files = ["spec/extlib/mash_spec.rb", "spec/extlib/hash_spec.rb", "spec/support/gorillib_test_helpers.rb", "spec/support/hashlike_helper.rb", "spec/support/shared_examples/included_module.rb", "spec/support/hashlike_fuzzing_helper.rb", "spec/support/matchers/be_hash_eql.rb", "spec/support/matchers/be_array_eql.rb", "spec/support/matchers/enumerate_method.rb", "spec/support/matchers/evaluate_to_true.rb", "spec/support/model_test_helpers.rb", "spec/support/factory_test_helpers.rb", "spec/support/hashlike_via_delegation.rb", "spec/support/hashlike_struct_helper.rb", "spec/gorillib/model_spec.rb", "spec/gorillib/builder_spec.rb", "spec/gorillib/numeric/clamp_spec.rb", "spec/gorillib/string/human_spec.rb", "spec/gorillib/string/inflections_spec.rb", "spec/gorillib/string/inflector_test_cases.rb", "spec/gorillib/string/constantize_spec.rb", "spec/gorillib/string/truncate_spec.rb", "spec/gorillib/metaprogramming/class_attribute_spec.rb", "spec/gorillib/metaprogramming/singleton_class_spec.rb", "spec/gorillib/metaprogramming/delegation_spec.rb", "spec/gorillib/hashlike_spec.rb", "spec/gorillib/exception/raisers_spec.rb", "spec/gorillib/utils/capture_output_spec.rb", "spec/gorillib/collection_spec.rb", "spec/gorillib/type/extended_spec.rb", "spec/gorillib/hash/zip_spec.rb", "spec/gorillib/hash/reverse_merge_spec.rb", "spec/gorillib/hash/slice_spec.rb", "spec/gorillib/hash/keys_spec.rb", "spec/gorillib/hash/compact_spec.rb", "spec/gorillib/hash/deep_compact_spec.rb", "spec/gorillib/hash/deep_merge_spec.rb", "spec/gorillib/datetime/parse_spec.rb", "spec/gorillib/datetime/to_flat_spec.rb", "spec/gorillib/hashlike/deep_hash_spec.rb", "spec/gorillib/hashlike/hashlike_behavior_spec.rb", "spec/gorillib/hashlike/hashlike_via_accessors_spec.rb", "spec/gorillib/hashlike/behave_same_as_hash_spec.rb", "spec/gorillib/configurable_spec.rb", "spec/gorillib/model/
|
216
|
+
s.test_files = ["spec/extlib/mash_spec.rb", "spec/extlib/hash_spec.rb", "spec/support/gorillib_test_helpers.rb", "spec/support/hashlike_helper.rb", "spec/support/shared_examples/included_module.rb", "spec/support/hashlike_fuzzing_helper.rb", "spec/support/matchers/be_hash_eql.rb", "spec/support/matchers/be_array_eql.rb", "spec/support/matchers/enumerate_method.rb", "spec/support/matchers/evaluate_to_true.rb", "spec/support/model_test_helpers.rb", "spec/support/factory_test_helpers.rb", "spec/support/hashlike_via_delegation.rb", "spec/support/hashlike_struct_helper.rb", "spec/gorillib/model_spec.rb", "spec/gorillib/builder_spec.rb", "spec/gorillib/numeric/clamp_spec.rb", "spec/gorillib/string/human_spec.rb", "spec/gorillib/string/inflections_spec.rb", "spec/gorillib/string/inflector_test_cases.rb", "spec/gorillib/string/constantize_spec.rb", "spec/gorillib/string/truncate_spec.rb", "spec/gorillib/metaprogramming/class_attribute_spec.rb", "spec/gorillib/metaprogramming/singleton_class_spec.rb", "spec/gorillib/metaprogramming/delegation_spec.rb", "spec/gorillib/hashlike_spec.rb", "spec/gorillib/exception/raisers_spec.rb", "spec/gorillib/utils/capture_output_spec.rb", "spec/gorillib/collection_spec.rb", "spec/gorillib/type/extended_spec.rb", "spec/gorillib/type/ip_address_spec.rb", "spec/gorillib/hash/zip_spec.rb", "spec/gorillib/hash/reverse_merge_spec.rb", "spec/gorillib/hash/slice_spec.rb", "spec/gorillib/hash/keys_spec.rb", "spec/gorillib/hash/compact_spec.rb", "spec/gorillib/hash/deep_compact_spec.rb", "spec/gorillib/hash/deep_merge_spec.rb", "spec/gorillib/datetime/parse_spec.rb", "spec/gorillib/datetime/to_flat_spec.rb", "spec/gorillib/hashlike/deep_hash_spec.rb", "spec/gorillib/hashlike/hashlike_behavior_spec.rb", "spec/gorillib/hashlike/hashlike_via_accessors_spec.rb", "spec/gorillib/hashlike/behave_same_as_hash_spec.rb", "spec/gorillib/configurable_spec.rb", "spec/gorillib/factories_spec.rb", "spec/gorillib/model/serialization/tsv_spec.rb", "spec/gorillib/model/lint_spec.rb", "spec/gorillib/model/defaults_spec.rb", "spec/gorillib/model/serialization_spec.rb", "spec/gorillib/model/overlay_spec.rb", "spec/gorillib/pathname_spec.rb", "spec/gorillib/enumerable/sum_spec.rb", "spec/gorillib/object/try_spec.rb", "spec/gorillib/object/blank_spec.rb", "spec/gorillib/object/try_dup_spec.rb", "spec/gorillib/array/compact_blank_spec.rb", "spec/gorillib/array/simple_statistics_spec.rb", "spec/gorillib/array/extract_options_spec.rb", "spec/gorillib/array/hashify_spec.rb", "spec/gorillib/logger/log_spec.rb", "spec/spec_helper.rb", "spec/examples/builder/ironfan_spec.rb"]
|
190
217
|
|
191
218
|
if s.respond_to? :specification_version then
|
192
219
|
s.specification_version = 3
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class Array
|
2
|
+
#
|
3
|
+
# Gets value of block on each element;
|
4
|
+
# constructs a hash of element-value pairs
|
5
|
+
#
|
6
|
+
# @return [Hash] hash of key-value pairs
|
7
|
+
def hashify
|
8
|
+
raise ArgumentError, 'hashify requires a block' unless block_given?
|
9
|
+
Hash[ self.map{|el| [el, yield(el)] } ]
|
10
|
+
end
|
11
|
+
end
|
data/lib/gorillib/base.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
require '
|
1
|
+
require 'multi_json'
|
2
|
+
|
3
|
+
require 'gorillib/base'
|
2
4
|
require 'gorillib/array/wrap'
|
3
5
|
require 'gorillib/type/extended'
|
4
6
|
require 'gorillib/hash/slice'
|
@@ -6,3 +8,8 @@ require 'gorillib/pathname'
|
|
6
8
|
require 'gorillib/logger/log'
|
7
9
|
require 'gorillib/model'
|
8
10
|
require 'gorillib/factories'
|
11
|
+
require 'gorillib/model/serialization'
|
12
|
+
require 'gorillib/model/serialization/csv'
|
13
|
+
require 'gorillib/model/serialization/tsv'
|
14
|
+
require 'gorillib/model/serialization/json'
|
15
|
+
require 'gorillib/model/indexable'
|
@@ -25,7 +25,7 @@ Exception.class_eval do
|
|
25
25
|
# end
|
26
26
|
#
|
27
27
|
def polish(extra_info)
|
28
|
-
filename, _, method_name = self.class.caller_parts
|
28
|
+
filename, _, method_name = self.class.caller_parts(2)
|
29
29
|
method_name.gsub!(/rescue in /, '')
|
30
30
|
most_recent_line = backtrace.detect{|line|
|
31
31
|
line.include?(filename) && line.include?(method_name) && line.end_with?("'") }
|
@@ -102,6 +102,11 @@ class ArgumentError
|
|
102
102
|
raise self, message, *args
|
103
103
|
end
|
104
104
|
|
105
|
+
|
106
|
+
def self.block_required!(block)
|
107
|
+
raise self.new("Block is required") unless block
|
108
|
+
end
|
109
|
+
|
105
110
|
#
|
106
111
|
# @param obj [Object] Object to check
|
107
112
|
# @param types [Array[Symbol,Class,Module]] Types or methods to compare
|
data/lib/gorillib/factories.rb
CHANGED
@@ -32,19 +32,6 @@ module Gorillib
|
|
32
32
|
klass.new(options)
|
33
33
|
end
|
34
34
|
|
35
|
-
# Manufactures objects from their raw attributes hash
|
36
|
-
#
|
37
|
-
# A hash with a value for `:_type` is dispatched to the corresponding factory
|
38
|
-
# Everything else is returned directly
|
39
|
-
def self.make(obj)
|
40
|
-
if obj.respond_to?(:has_key?) && (obj.has_key?(:_type) || obj.has_key?('_type'))
|
41
|
-
factory = Gorillib::Factory(attrs[:_type])
|
42
|
-
factory.receive(obj)
|
43
|
-
else
|
44
|
-
obj
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
35
|
def self.register_factory(factory, typenames)
|
49
36
|
typenames.each{|typename| factories[typename] = factory }
|
50
37
|
end
|
@@ -185,6 +172,14 @@ module Gorillib
|
|
185
172
|
end
|
186
173
|
end
|
187
174
|
|
175
|
+
# __________________________________________________________________________
|
176
|
+
#
|
177
|
+
# Generic Factories
|
178
|
+
# __________________________________________________________________________
|
179
|
+
|
180
|
+
#
|
181
|
+
# Factory that accepts whatever given and uses it directly -- no nothin'
|
182
|
+
#
|
188
183
|
class ::Whatever < BaseFactory
|
189
184
|
def initialize(options={})
|
190
185
|
options.slice!(:convert, :blankish)
|
@@ -200,6 +195,24 @@ module Gorillib
|
|
200
195
|
end
|
201
196
|
IdenticalFactory = ::Whatever unless defined?(IdenticalFactory)
|
202
197
|
|
198
|
+
|
199
|
+
# Manufactures objects from their raw attributes hash
|
200
|
+
#
|
201
|
+
# The hash must have a value for `:_type`, used to retrieve the actual factory
|
202
|
+
#
|
203
|
+
class ::GenericModel < BaseFactory
|
204
|
+
def blankish?(obj) obj.nil? ; end
|
205
|
+
def native?(obj) false ; end
|
206
|
+
def receive(attrs, &block)
|
207
|
+
Gorillib::Model::Validate.hashlike!(attrs){ "attributes for typed object" }
|
208
|
+
klass = Gorillib::Factory(attrs.fetch(:_type){ attrs.fetch("_type") })
|
209
|
+
#
|
210
|
+
klass.new(attrs, &block)
|
211
|
+
end
|
212
|
+
def self.receive(obj) allocate.receive(obj) end
|
213
|
+
register_factory!(GenericModel, :generic)
|
214
|
+
end
|
215
|
+
|
203
216
|
# __________________________________________________________________________
|
204
217
|
#
|
205
218
|
# Concrete Factories
|
data/lib/gorillib/model/base.rb
CHANGED
@@ -31,6 +31,7 @@ module Gorillib
|
|
31
31
|
# @return [{Symbol => Object}] The Hash of all attributes
|
32
32
|
def attributes
|
33
33
|
self.class.field_names.inject(Hash.new) do |hsh, fn|
|
34
|
+
# hsh[fn] = attribute_set?(fn) ? read_attribute(fn) : nil
|
34
35
|
hsh[fn] = read_attribute(fn)
|
35
36
|
hsh
|
36
37
|
end
|
@@ -199,6 +200,10 @@ module Gorillib
|
|
199
200
|
str << '>'
|
200
201
|
end
|
201
202
|
|
203
|
+
def to_s
|
204
|
+
inspect
|
205
|
+
end
|
206
|
+
|
202
207
|
def inspect_compact
|
203
208
|
str = "#<#{self.class.name.to_s}>"
|
204
209
|
end
|
@@ -208,7 +213,6 @@ module Gorillib
|
|
208
213
|
def to_inspectable
|
209
214
|
compact_attributes
|
210
215
|
end
|
211
|
-
private :to_inspectable
|
212
216
|
|
213
217
|
protected
|
214
218
|
|
@@ -260,6 +264,7 @@ module Gorillib
|
|
260
264
|
base.instance_eval do
|
261
265
|
extend Gorillib::Model::NamedSchema
|
262
266
|
extend Gorillib::Model::ClassMethods
|
267
|
+
self.meta_module
|
263
268
|
@_own_fields ||= {}
|
264
269
|
end
|
265
270
|
end
|
@@ -21,9 +21,11 @@ module Gorillib
|
|
21
21
|
def each_in_csv(filename, options={})
|
22
22
|
filename = Pathname.path_to(filename)
|
23
23
|
options = csv_options.merge(options)
|
24
|
+
#
|
24
25
|
pop_headers = options.delete(:pop_headers)
|
25
26
|
num_fields = options.delete(:num_fields){ (fields.length .. fields.length) }
|
26
27
|
raise ArgumentError, "The :headers option to CSV changes its internal behavior; use 'pop_headers: true' to ignore the first line" if options[:headers]
|
28
|
+
#
|
27
29
|
CSV.open(filename, options) do |csv_file|
|
28
30
|
csv_file.shift if pop_headers
|
29
31
|
csv_file.each do |tuple|
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require_relative './lines'
|
2
|
+
|
3
|
+
module Gorillib
|
4
|
+
module Model
|
5
|
+
|
6
|
+
module LoadFromJson
|
7
|
+
extend Gorillib::Concern
|
8
|
+
include LoadLines
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
|
12
|
+
# Iterate a block over each line of a file having JSON records, one per
|
13
|
+
# line, in a big stack
|
14
|
+
#
|
15
|
+
# @yield an object instantiated from each line in the file.
|
16
|
+
def _each_from_json(filename, options={})
|
17
|
+
_each_raw_line(filename, options) do |line|
|
18
|
+
hsh = MultiJson.load(line)
|
19
|
+
yield receive(hsh)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# With a block, calls block on each object in turn (and returns nil)
|
24
|
+
#
|
25
|
+
# With no block, accumulates all the instances into the array it
|
26
|
+
# returns. As opposed to the with-a-block case, the memory footprint of
|
27
|
+
# this increases as the filesize does, so use caution with large files.
|
28
|
+
#
|
29
|
+
# @return with a block, returns nil; with no block, an array of this class' instances
|
30
|
+
def load_json(*args)
|
31
|
+
if block_given?
|
32
|
+
_each_from_json(*args, &Proc.new)
|
33
|
+
else
|
34
|
+
objs = []
|
35
|
+
_each_from_json(*args){|obj| objs << obj }
|
36
|
+
objs
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Gorillib
|
2
|
+
module Model
|
3
|
+
|
4
|
+
module LoadLines
|
5
|
+
extend Gorillib::Concern
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
|
9
|
+
# Iterate a block over each line of a file
|
10
|
+
# @yield each line in the file.
|
11
|
+
def _each_raw_line(filename, options={})
|
12
|
+
filename = Pathname.path_to(filename)
|
13
|
+
#
|
14
|
+
pop_headers = options.delete(:pop_headers)
|
15
|
+
#
|
16
|
+
File.open(filename) do |file|
|
17
|
+
file.readline if pop_headers
|
18
|
+
file.each do |line|
|
19
|
+
line.chomp! ; next if line.empty?
|
20
|
+
yield line
|
21
|
+
end
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require_relative './lines'
|
2
|
+
|
3
|
+
module Gorillib
|
4
|
+
module Model
|
5
|
+
|
6
|
+
module LoadFromTsv
|
7
|
+
extend Gorillib::Concern
|
8
|
+
include LoadLines
|
9
|
+
|
10
|
+
included do |base|
|
11
|
+
# Options that will be passed to CSV. Be careful to modify with assignment (`+=`) and not in-place (`<<`)
|
12
|
+
base.class_attribute :tsv_options
|
13
|
+
base.tsv_options = Hash.new
|
14
|
+
end
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
|
18
|
+
# Iterate a block over each line of a TSV file
|
19
|
+
#
|
20
|
+
# @raise [Gorillib::Model::RawDataMismatchError] if a line has too many or too few fields
|
21
|
+
# @yield an object instantiated from each line in the file.
|
22
|
+
def _each_from_tsv(filename, options={})
|
23
|
+
options = tsv_options.merge(options)
|
24
|
+
num_fields = options.delete(:num_fields){ (fields.length .. fields.length) }
|
25
|
+
max_fields = num_fields.max # need to make sure "1\t2\t\t\t" becomes ["1","2","","",""]
|
26
|
+
#
|
27
|
+
_each_raw_line(filename, options) do |line|
|
28
|
+
tuple = line.split("\t", max_fields)
|
29
|
+
unless num_fields.include?(tuple.length) then raise Gorillib::Model::RawDataMismatchError, "yark, spurious fields: #{tuple.inspect}" ; end
|
30
|
+
yield from_tuple(*tuple)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# With a block, calls block on each object in turn (and returns nil)
|
35
|
+
#
|
36
|
+
# With no block, accumulates all the instances into the array it
|
37
|
+
# returns. As opposed to the with-a-block case, the memory footprint of
|
38
|
+
# this increases as the filesize does, so use caution with large files.
|
39
|
+
#
|
40
|
+
# @return with a block, returns nil; with no block, an array of this class' instances
|
41
|
+
def load_tsv(*args)
|
42
|
+
if block_given?
|
43
|
+
_each_from_tsv(*args, &Proc.new)
|
44
|
+
else
|
45
|
+
objs = []
|
46
|
+
_each_from_tsv(*args){|obj| objs << obj }
|
47
|
+
objs
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class Pathname
|
2
|
+
# same as `#exist?`
|
3
|
+
def exists?(*args) exist?(*args) ; end
|
4
|
+
|
5
|
+
# @example It chains nicely:
|
6
|
+
# # put each file in eg. dest/f/foo.json
|
7
|
+
# Pathname.of(:dest, slug[0..0], "#{slug}.json").mkparent.open('w') do |file|
|
8
|
+
# # ...
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# @returns the path itself (not its parent)
|
12
|
+
def mkparent
|
13
|
+
dirname.mkpath
|
14
|
+
return self
|
15
|
+
end
|
16
|
+
|
17
|
+
#
|
18
|
+
# Executes the block (passing the opened file) if the file does not
|
19
|
+
# exist. Ignores the block otherwise. The block is required.
|
20
|
+
#
|
21
|
+
# @param options
|
22
|
+
# @option options[:force] Force creation of the file
|
23
|
+
#
|
24
|
+
# @returns the path itself (not the file)
|
25
|
+
def if_missing(options={}, &block)
|
26
|
+
ArgumentError.block_required!(block)
|
27
|
+
return self if exist? && (not options[:force])
|
28
|
+
#
|
29
|
+
mkparent
|
30
|
+
open((options[:mode] || 'w'), &block)
|
31
|
+
return self
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|