cascade-rb 0.1.2 → 0.1.5
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.
- checksums.yaml +4 -4
- data/README.md +105 -8
- data/cascade.gemspec +1 -1
- data/lib/cascade.rb +1 -0
- data/lib/cascade/error_handler.rb +11 -1
- data/lib/cascade/helpers/hash.rb +6 -2
- data/lib/cascade/version.rb +1 -1
- data/spec/lib/error_handler_spec.rb +8 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e76a5428ad502dfd46ba38144264758b9db61701
|
4
|
+
data.tar.gz: c806af678c7b76c650100d0468b10894d6fd1e6d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 81b4fee7d44a42ae18deea8c2cb61c7629bd56703350833f9cd0e3e52b01b1809c38e8a4c709d9cdfe7c596c9680e4079fb8c5c18b0cc289d4d118b67e6e0425
|
7
|
+
data.tar.gz: 12fb5bf658fd193b8dd92a45f90b9de140f834f534e3902fe0948f90b7507fdd6bb73a789ce70a9feeb12bed6e4901232eb886855046b22d47b6b77dc9c2af32
|
data/README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# [Cascade]
|
2
2
|
|
3
|
-
[](https://codeship.com/projects/63625) [](https://codeclimate.com/github/ignat-zakrevsky/cascade) [](https://codeclimate.com/github/ignat-zakrevsky/cascade)
|
3
|
+
[](https://codeship.com/projects/63625) [](https://codeclimate.com/github/ignat-zakrevsky/cascade) [](https://codeclimate.com/github/ignat-zakrevsky/cascade) [](http://badge.fury.io/rb/cascade-rb)
|
4
4
|
|
5
|
-
The main aim of this
|
5
|
+
The main aim of this gem is to provide some kind of template for parsing files.
|
6
6
|
Usually, parsing file process contains next steps:
|
7
7
|
|
8
8
|
1. Retreiving info from file
|
@@ -15,11 +15,108 @@ Usually, parsing file process contains next steps:
|
|
15
15
|
|
16
16
|
Cascade pretends to simplify main part of this step to save your time.
|
17
17
|
|
18
|
+
## Examples
|
19
|
+
|
20
|
+
[Minimal working example](https://github.com/ignat-zakrevsky/cascade-example)
|
21
|
+
|
22
|
+
[More complicated example](https://github.com/ignat-zakrevsky/cascade-example/tree/json-example)
|
23
|
+
|
24
|
+
## Installation
|
25
|
+
Install the cascade-rb package from Rubygems:
|
26
|
+
```
|
27
|
+
gem install cascade-rb
|
28
|
+
```
|
29
|
+
|
30
|
+
or add it to your Gemfile for Bundler:
|
31
|
+
```ruby
|
32
|
+
gem 'cascade-rb'
|
33
|
+
```
|
34
|
+
|
18
35
|
## Usage
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
36
|
+
Require gem files
|
37
|
+
```ruby
|
38
|
+
require 'cascade'
|
39
|
+
```
|
40
|
+
|
41
|
+
Configure it!
|
42
|
+
```ruby
|
43
|
+
Cascade.configuration do
|
44
|
+
# [Object#call] will be used for undefined fields types
|
45
|
+
Cascade::RowProcessor.deafult_presenter
|
46
|
+
# [Boolean] will throw exception in case of unavailable presenter
|
47
|
+
Cascade::RowProcessor.use_default_presenter
|
48
|
+
# [String] filepath with columns mapping, see below
|
49
|
+
Cascade::ColumnsMatching.mapping_file
|
50
|
+
# [Boolean] will raise fields parsing exceptions
|
51
|
+
Cascade::ErrorHandler.raise_parse_errors
|
52
|
+
end
|
53
|
+
```
|
54
|
+
|
55
|
+
Provide file for parsing and run it!
|
56
|
+
```ruby
|
57
|
+
Cascade::DataParser.new("data_test.txt").call
|
58
|
+
```
|
59
|
+
|
60
|
+
## Columns mapping
|
61
|
+
Parsing file description should have next structure [(example)](https://github.com/ignat-zakrevsky/cascade-example/blob/master/columns_mapping.yml)
|
62
|
+
```yaml
|
63
|
+
mapping:
|
64
|
+
name: type
|
65
|
+
```
|
66
|
+
|
67
|
+
## Columns parsing
|
68
|
+
There are several alredy defined fields parsers (types):
|
69
|
+
|
70
|
+
- currency
|
71
|
+
- boolean
|
72
|
+
- country_iso
|
73
|
+
- string
|
74
|
+
|
75
|
+
Feel free to add new fields parsers and provide it through PR.
|
25
76
|
|
77
|
+
## Components replaceability
|
78
|
+
There is a lot of DI in this gem, so, you can replace each component of the parser. Let's assume you want to parse JSON files instead of CSV, save this to ActiveRecord model, and you need Date fields parsing, ok!
|
79
|
+
Writing new data provider:
|
80
|
+
```ruby
|
81
|
+
class ParserJSON
|
82
|
+
def open(file)
|
83
|
+
JSON.parse(File.read(file))["rows"]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
```
|
87
|
+
Writing new data saver:
|
88
|
+
```ruby
|
89
|
+
class PersonDataSaver
|
90
|
+
def call(person_data)
|
91
|
+
Person.create!(person_data)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
```
|
95
|
+
considering that there is no much logic even better
|
96
|
+
```ruby
|
97
|
+
PERSON_SAVER = -> (person_data) { Person.create!(person_data) }
|
98
|
+
```
|
99
|
+
Writing date parser:
|
100
|
+
```ruby
|
101
|
+
class DateParser
|
102
|
+
def call(value)
|
103
|
+
Date.parse(value)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
```
|
107
|
+
or you can always use lambdas for such logic
|
108
|
+
```ruby
|
109
|
+
DATE_PARSER = -> (value) { Date.parse(value) }
|
110
|
+
```
|
111
|
+
Provide all this stuff into data parser
|
112
|
+
```ruby
|
113
|
+
Cascade::DataParser.new("data_test.json",
|
114
|
+
row_processor: Cascade::RowProcessor.new(date: DateParser.new),
|
115
|
+
data_provider: ParserJSON.new,
|
116
|
+
data_saver: PERSON_SAVER
|
117
|
+
).call
|
118
|
+
```
|
119
|
+
And that's all!
|
120
|
+
[Example](https://github.com/ignat-zakrevsky/cascade-example/blob/json-example/main.rb)
|
121
|
+
## Conventions
|
122
|
+
I'm fan of callable object as consequence I prefer #call methods for classes with one responsibility. [Nice video](http://www.rubytapas.com/episodes/35-Callable) that describes benefits of such approach
|
data/cascade.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ["Ignat Zakrevsky"]
|
10
10
|
spec.email = %w(iezakrevsky@gmail.com)
|
11
11
|
spec.summary = "Ruby data parser gem."
|
12
|
-
spec.description = "Highly customizable
|
12
|
+
spec.description = "Highly customizable data parser with a lot of DI"
|
13
13
|
spec.homepage = "https://github.com/ignat-zakrevsky/cascade"
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
data/lib/cascade.rb
CHANGED
@@ -1,5 +1,11 @@
|
|
1
|
+
require "cascade/helpers/configuration"
|
2
|
+
|
1
3
|
module Cascade
|
2
4
|
class ErrorHandler
|
5
|
+
extend Configuration
|
6
|
+
|
7
|
+
define_setting :raise_parse_errors, false
|
8
|
+
|
3
9
|
HANDLING_EXCEPTIONS = [IsoCountryCodes::UnknownCodeError, IndexError]
|
4
10
|
DEFAULT_ERROR_STORE = ->(row, reason) do
|
5
11
|
@errors ||= []
|
@@ -8,6 +14,9 @@ module Cascade
|
|
8
14
|
|
9
15
|
def initialize(options = {})
|
10
16
|
@error_store = options.fetch(:error_store) { DEFAULT_ERROR_STORE }
|
17
|
+
@handling_exceptions = options.fetch(:handling_exceptions) do
|
18
|
+
HANDLING_EXCEPTIONS
|
19
|
+
end
|
11
20
|
end
|
12
21
|
|
13
22
|
# Runs passed block with catching throwing errors and storing in ErrorStore
|
@@ -16,8 +25,9 @@ module Cascade
|
|
16
25
|
# problems with processing
|
17
26
|
def with_errors_handling(row)
|
18
27
|
yield
|
19
|
-
rescue
|
28
|
+
rescue *@handling_exceptions => exception
|
20
29
|
@error_store.call(row, exception.to_s)
|
30
|
+
raise exception if self.class.raise_parse_errors
|
21
31
|
end
|
22
32
|
end
|
23
33
|
end
|
data/lib/cascade/helpers/hash.rb
CHANGED
data/lib/cascade/version.rb
CHANGED
@@ -21,6 +21,14 @@ describe Cascade::ErrorHandler do
|
|
21
21
|
subject.with_errors_handling(row) { raise exception }
|
22
22
|
assert_includes @errors, [row, exception.to_s]
|
23
23
|
end
|
24
|
+
|
25
|
+
it "raises #{exception} if raise_parse_errors setting is true" do
|
26
|
+
described_class.stub(:raise_parse_errors, true) do
|
27
|
+
assert_raises(exception) do
|
28
|
+
subject.with_errors_handling(row) { raise exception }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
24
32
|
end
|
25
33
|
|
26
34
|
describe "DEFAULT_ERROR_STORE" do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cascade-rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ignat Zakrevsky
|
@@ -178,7 +178,7 @@ dependencies:
|
|
178
178
|
- - ">="
|
179
179
|
- !ruby/object:Gem::Version
|
180
180
|
version: '0'
|
181
|
-
description: Highly customizable
|
181
|
+
description: Highly customizable data parser with a lot of DI
|
182
182
|
email:
|
183
183
|
- iezakrevsky@gmail.com
|
184
184
|
executables: []
|
@@ -189,7 +189,6 @@ files:
|
|
189
189
|
- ".hound.yml"
|
190
190
|
- ".ruby-style.yml"
|
191
191
|
- Gemfile
|
192
|
-
- Gemfile.lock
|
193
192
|
- README.md
|
194
193
|
- Rakefile
|
195
194
|
- cascade.gemspec
|
@@ -276,3 +275,4 @@ test_files:
|
|
276
275
|
- spec/lib/statistics_stores/array_store_spec.rb
|
277
276
|
- spec/lib/statistics_stores/counter_store_spec.rb
|
278
277
|
- spec/spec_helper.rb
|
278
|
+
has_rdoc:
|