scripper 0.1.0 → 0.1.1
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/.gitignore +14 -13
- data/.rspec +3 -3
- data/.rubocop.yml +27 -27
- data/.travis.yml +20 -20
- data/Gemfile +5 -5
- data/LICENSE +21 -21
- data/README.md +164 -164
- data/Rakefile +8 -8
- data/lib/scripper.rb +8 -8
- data/lib/scripper/sequel.rb +25 -25
- data/lib/scripper/sequel/dataset_stripper.rb +14 -14
- data/lib/scripper/sequel/model_stripper.rb +69 -63
- data/lib/scripper/sequel/value_converter.rb +23 -23
- data/scripper.gemspec +35 -35
- metadata +2 -3
- data/Gemfile.lock +0 -104
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 23ae9ed50d0a9424206847fc397358c0e496b45f0ffec8627b0710043fc863de
|
|
4
|
+
data.tar.gz: 7308b47894cf9d3c430fc21586827e00e6a7eaa249cc65ae7a779c4fa8f53a59
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1810dd1a45876ac927cb652b742fa3b63ecbedbf086ed670a258df9b6707ea539e4dff58f7361f44e13a504cf90e170e40658a6336469776f5f5270abe287278
|
|
7
|
+
data.tar.gz: 24d08010518e9232d7be7ffcc6d261060803e4bf4f5416e836fa514603fe8fd87e6c56080df3a923e135924615bb665a0a0ae4df8e9b2c445405f5b49f687885
|
data/.gitignore
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
/.bundle/
|
|
2
|
-
/.yardoc
|
|
3
|
-
/_yardoc/
|
|
4
|
-
/coverage/
|
|
5
|
-
/doc/
|
|
6
|
-
/pkg/
|
|
7
|
-
/spec/reports/
|
|
8
|
-
/tmp/
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
/.bundle/
|
|
2
|
+
/.yardoc
|
|
3
|
+
/_yardoc/
|
|
4
|
+
/coverage/
|
|
5
|
+
/doc/
|
|
6
|
+
/pkg/
|
|
7
|
+
/spec/reports/
|
|
8
|
+
/tmp/
|
|
9
|
+
/Gemfile.lock
|
|
10
|
+
|
|
11
|
+
# rspec failure tracking
|
|
12
|
+
.rspec_status
|
|
13
|
+
|
|
14
|
+
/scripper-*.gem
|
data/.rspec
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
--format documentation
|
|
2
|
-
--color
|
|
3
|
-
--require spec_helper
|
|
1
|
+
--format documentation
|
|
2
|
+
--color
|
|
3
|
+
--require spec_helper
|
data/.rubocop.yml
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
inherit_gem:
|
|
2
|
-
rubocop-config-umbrellio: lib/rubocop.yml
|
|
3
|
-
armitage-rubocop:
|
|
4
|
-
- lib/rubocop.general.yml
|
|
5
|
-
- lib/rubocop.rspec.yml
|
|
6
|
-
|
|
7
|
-
AllCops:
|
|
8
|
-
TargetRubyVersion: 2.6.3
|
|
9
|
-
Include:
|
|
10
|
-
- sequel-connection_guard.gemspec
|
|
11
|
-
- lib/**/*.rb
|
|
12
|
-
- spec/**/*.rb
|
|
13
|
-
- Gemfile
|
|
14
|
-
- Rakefile
|
|
15
|
-
- bin/console
|
|
16
|
-
|
|
17
|
-
Style/TrailingCommaInArguments:
|
|
18
|
-
EnforcedStyleForMultiline: comma
|
|
19
|
-
|
|
20
|
-
Style/TrailingCommaInArrayLiteral:
|
|
21
|
-
EnforcedStyleForMultiline: comma
|
|
22
|
-
|
|
23
|
-
Style/TrailingCommaInHashLiteral:
|
|
24
|
-
EnforcedStyleForMultiline: comma
|
|
25
|
-
|
|
26
|
-
RSpec/LeakyConstantDeclaration:
|
|
27
|
-
Enabled: false
|
|
1
|
+
inherit_gem:
|
|
2
|
+
rubocop-config-umbrellio: lib/rubocop.yml
|
|
3
|
+
armitage-rubocop:
|
|
4
|
+
- lib/rubocop.general.yml
|
|
5
|
+
- lib/rubocop.rspec.yml
|
|
6
|
+
|
|
7
|
+
AllCops:
|
|
8
|
+
TargetRubyVersion: 2.6.3
|
|
9
|
+
Include:
|
|
10
|
+
- sequel-connection_guard.gemspec
|
|
11
|
+
- lib/**/*.rb
|
|
12
|
+
- spec/**/*.rb
|
|
13
|
+
- Gemfile
|
|
14
|
+
- Rakefile
|
|
15
|
+
- bin/console
|
|
16
|
+
|
|
17
|
+
Style/TrailingCommaInArguments:
|
|
18
|
+
EnforcedStyleForMultiline: comma
|
|
19
|
+
|
|
20
|
+
Style/TrailingCommaInArrayLiteral:
|
|
21
|
+
EnforcedStyleForMultiline: comma
|
|
22
|
+
|
|
23
|
+
Style/TrailingCommaInHashLiteral:
|
|
24
|
+
EnforcedStyleForMultiline: comma
|
|
25
|
+
|
|
26
|
+
RSpec/LeakyConstantDeclaration:
|
|
27
|
+
Enabled: false
|
data/.travis.yml
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
sudo: false
|
|
2
|
-
language: ruby
|
|
3
|
-
rvm:
|
|
4
|
-
- 2.5.1
|
|
5
|
-
- 2.6
|
|
6
|
-
- ruby-head
|
|
7
|
-
|
|
8
|
-
services:
|
|
9
|
-
- postgresql
|
|
10
|
-
addons:
|
|
11
|
-
postgresql: 9.6
|
|
12
|
-
|
|
13
|
-
before_install: gem install bundler
|
|
14
|
-
before_script:
|
|
15
|
-
- psql -c 'create database scripper_test;' -U postgres
|
|
16
|
-
script:
|
|
17
|
-
- bundle exec rspec
|
|
18
|
-
- bundle exec rubocop
|
|
19
|
-
|
|
20
|
-
cache: bundler
|
|
1
|
+
sudo: false
|
|
2
|
+
language: ruby
|
|
3
|
+
rvm:
|
|
4
|
+
- 2.5.1
|
|
5
|
+
- 2.6
|
|
6
|
+
- ruby-head
|
|
7
|
+
|
|
8
|
+
services:
|
|
9
|
+
- postgresql
|
|
10
|
+
addons:
|
|
11
|
+
postgresql: 9.6
|
|
12
|
+
|
|
13
|
+
before_install: gem install bundler
|
|
14
|
+
before_script:
|
|
15
|
+
- psql -c 'create database scripper_test;' -U postgres
|
|
16
|
+
script:
|
|
17
|
+
- bundle exec rspec
|
|
18
|
+
- bundle exec rubocop
|
|
19
|
+
|
|
20
|
+
cache: bundler
|
data/Gemfile
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
source "https://rubygems.org"
|
|
4
|
-
|
|
5
|
-
gemspec
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
source "https://rubygems.org"
|
|
4
|
+
|
|
5
|
+
gemspec
|
data/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
The MIT License (MIT)
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2019 Umbrellio
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in
|
|
13
|
-
all copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
-
THE SOFTWARE.
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2019 Umbrellio
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
CHANGED
|
@@ -1,164 +1,164 @@
|
|
|
1
|
-
# Scripper
|
|
2
|
-
[](https://travis-ci.org/umbrellio/scripper)
|
|
3
|
-
[](https://coveralls.io/github/umbrellio/scripper?branch=master)
|
|
4
|
-
[](https://badge.fury.io/rb/scripper)
|
|
5
|
-
|
|
6
|
-
This gem allows you to strip down your Sequel model instances and hashes returned by dataset queries
|
|
7
|
-
to simple Ruby structs.
|
|
8
|
-
|
|
9
|
-
**This gem was only tested against PostgreSQL databases.**
|
|
10
|
-
|
|
11
|
-
## Why strip models?
|
|
12
|
-
|
|
13
|
-
It's often convenient to simply call methods on model objects everywhere: controllers, views,
|
|
14
|
-
serializers, business logic, and so on. But, by doing so, you're making the whole of your codebase
|
|
15
|
-
depend on your database!
|
|
16
|
-
|
|
17
|
-
This gem is a very basic way to introduce some layer of isolation between your database and the
|
|
18
|
-
rest of the codebase. As your application grows, it will be much simpler to transition to more
|
|
19
|
-
mature abstractions with such isolation than without it.
|
|
20
|
-
|
|
21
|
-
The behaviour is more predictable since:
|
|
22
|
-
- There are no unexpected database queries (e.x. when loading associations during view rendering)
|
|
23
|
-
- There are no leaking database types like `Sequel::Postgres::JSONBHash` (these are converted to hashes automatically)
|
|
24
|
-
|
|
25
|
-
## Installation
|
|
26
|
-
|
|
27
|
-
Add this line to your application's Gemfile:
|
|
28
|
-
|
|
29
|
-
```ruby
|
|
30
|
-
gem 'scripper'
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
And then execute:
|
|
34
|
-
```sh
|
|
35
|
-
$ bundle
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
It's recommended to "wrap" this gem into a separate module:
|
|
39
|
-
```ruby
|
|
40
|
-
# lib/stripper.rb
|
|
41
|
-
|
|
42
|
-
Stripper = Scripper::Sequel
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
## Usage
|
|
46
|
-
|
|
47
|
-
It's very simple! Scripper works both with instances of Sequel::Model and hashes returned when
|
|
48
|
-
using naked models or datasets.
|
|
49
|
-
|
|
50
|
-
```ruby
|
|
51
|
-
# with models
|
|
52
|
-
user = User.first
|
|
53
|
-
Stripper.strip(user) # => #<struct id=2, email="cow@cow.cow", password_hash="...">
|
|
54
|
-
user.email # => "cow@cow.cow"
|
|
55
|
-
|
|
56
|
-
# with datasets
|
|
57
|
-
user = DB[:users].first # or: User.naked.first
|
|
58
|
-
Stripper.strip(user) # => #<struct id=2, email="cow@cow.cow", password_hash="...">
|
|
59
|
-
user.email # => "cow@cow.cow"
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
### Loading associations
|
|
63
|
-
|
|
64
|
-
If you'd like to also use associations on your struct (works only with models):
|
|
65
|
-
|
|
66
|
-
```ruby
|
|
67
|
-
user = User.first
|
|
68
|
-
Stripper.strip(user, with_associations: %w[cookies])
|
|
69
|
-
# => #<struct id=2, ..., cookies=[#<struct ...>, #<struct ...>, #<struct ...>]>
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
Beware that this will load _all_ cookies associated with your user! If you want to impose some
|
|
73
|
-
filtering conditions, you can do that:
|
|
74
|
-
|
|
75
|
-
```ruby
|
|
76
|
-
user = User.first
|
|
77
|
-
Stripper.strip(
|
|
78
|
-
user,
|
|
79
|
-
with_associations: { cookies: -> (ds) { ds.where(active: true).limit(10) } },
|
|
80
|
-
)
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
This will only load no more than 10 active cookies.
|
|
84
|
-
|
|
85
|
-
### Providing extra attributes
|
|
86
|
-
|
|
87
|
-
Sometimes it's useful to provide some context beyond associations and model/dataset attributes.
|
|
88
|
-
|
|
89
|
-
In the example below, we're providing information about user's payment sum, not only user's fields.
|
|
90
|
-
|
|
91
|
-
```ruby
|
|
92
|
-
# with a model
|
|
93
|
-
user = User
|
|
94
|
-
.left_join(:payments)
|
|
95
|
-
.select_all(:users)
|
|
96
|
-
.select_append(
|
|
97
|
-
Sequel.function(:sum, Sequel[:payments][:amount]).as(:payment_sum),
|
|
98
|
-
)
|
|
99
|
-
.group(Sequel[:users][:id])
|
|
100
|
-
.first
|
|
101
|
-
|
|
102
|
-
Stripper.strip(user, with_attributes: { payment_sum: user[:payment_sum] })
|
|
103
|
-
# => #<struct id=2, ..., payment_sum=418.0>
|
|
104
|
-
|
|
105
|
-
# with a dataset, it's nearly identical
|
|
106
|
-
user = DB[:users]
|
|
107
|
-
.left_join(:payments)
|
|
108
|
-
.select_all(:users)
|
|
109
|
-
.select_append(
|
|
110
|
-
Sequel.function(:sum, Sequel[:payments][:amount]).as(:payment_sum),
|
|
111
|
-
)
|
|
112
|
-
.group(Sequel[:users][:id])
|
|
113
|
-
.first
|
|
114
|
-
|
|
115
|
-
Stripper.strip(user, with_attributes: { payment_sum: user[:payment_sum] })
|
|
116
|
-
# => #<struct id=2, ..., payment_sum=418.0>
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
## Default value conversions
|
|
120
|
-
|
|
121
|
-
`Sequel::Postgres::JSONHashBase` (`JSONBHash`, `JSONHash`, ...) => `Hash`
|
|
122
|
-
|
|
123
|
-
`Sequel::Postgres::JSONArrayBase` (`JSONBArray`, `JSONArray`, ...) => `Array`
|
|
124
|
-
|
|
125
|
-
`Sequel::Postgres::PGArray` => `Array`
|
|
126
|
-
|
|
127
|
-
`BigDecimal` => `Float`
|
|
128
|
-
|
|
129
|
-
Currently, these are not extensible.
|
|
130
|
-
|
|
131
|
-
## Roadmap
|
|
132
|
-
|
|
133
|
-
It would be lovely to:
|
|
134
|
-
- Make value conversions extensible
|
|
135
|
-
- Support ActiveRecord
|
|
136
|
-
- Test the gem on other databases
|
|
137
|
-
|
|
138
|
-
Your contributions and feedback are very welcome!
|
|
139
|
-
|
|
140
|
-
## Development
|
|
141
|
-
|
|
142
|
-
To run tests, you need to first create a PostgreSQL database, and then set a `DB_URL` variable.
|
|
143
|
-
|
|
144
|
-
Example:
|
|
145
|
-
```sh
|
|
146
|
-
DB_URL=postgres://localhost/scripper_test bundle exec rspec
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
If you want to enable Sequel's database access logging during spec runs, use `LOG_DB=1`.
|
|
150
|
-
|
|
151
|
-
## Contributing
|
|
152
|
-
|
|
153
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/umbrellio/scripper.
|
|
154
|
-
|
|
155
|
-
## License
|
|
156
|
-
|
|
157
|
-
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
|
158
|
-
|
|
159
|
-
## Authors
|
|
160
|
-
Created by [Alexander Komarov](https://github.com/akxcv).
|
|
161
|
-
|
|
162
|
-
<a href="https://github.com/umbrellio/">
|
|
163
|
-
<img style="float: left;" src="https://umbrellio.github.io/Umbrellio/supported_by_umbrellio.svg" alt="Supported by Umbrellio" width="439" height="72">
|
|
164
|
-
</a>
|
|
1
|
+
# Scripper
|
|
2
|
+
[](https://travis-ci.org/umbrellio/scripper)
|
|
3
|
+
[](https://coveralls.io/github/umbrellio/scripper?branch=master)
|
|
4
|
+
[](https://badge.fury.io/rb/scripper)
|
|
5
|
+
|
|
6
|
+
This gem allows you to strip down your Sequel model instances and hashes returned by dataset queries
|
|
7
|
+
to simple Ruby structs.
|
|
8
|
+
|
|
9
|
+
**This gem was only tested against PostgreSQL databases.**
|
|
10
|
+
|
|
11
|
+
## Why strip models?
|
|
12
|
+
|
|
13
|
+
It's often convenient to simply call methods on model objects everywhere: controllers, views,
|
|
14
|
+
serializers, business logic, and so on. But, by doing so, you're making the whole of your codebase
|
|
15
|
+
depend on your database!
|
|
16
|
+
|
|
17
|
+
This gem is a very basic way to introduce some layer of isolation between your database and the
|
|
18
|
+
rest of the codebase. As your application grows, it will be much simpler to transition to more
|
|
19
|
+
mature abstractions with such isolation than without it.
|
|
20
|
+
|
|
21
|
+
The behaviour is more predictable since:
|
|
22
|
+
- There are no unexpected database queries (e.x. when loading associations during view rendering)
|
|
23
|
+
- There are no leaking database types like `Sequel::Postgres::JSONBHash` (these are converted to hashes automatically)
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
|
|
27
|
+
Add this line to your application's Gemfile:
|
|
28
|
+
|
|
29
|
+
```ruby
|
|
30
|
+
gem 'scripper'
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
And then execute:
|
|
34
|
+
```sh
|
|
35
|
+
$ bundle
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
It's recommended to "wrap" this gem into a separate module:
|
|
39
|
+
```ruby
|
|
40
|
+
# lib/stripper.rb
|
|
41
|
+
|
|
42
|
+
Stripper = Scripper::Sequel
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Usage
|
|
46
|
+
|
|
47
|
+
It's very simple! Scripper works both with instances of Sequel::Model and hashes returned when
|
|
48
|
+
using naked models or datasets.
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
# with models
|
|
52
|
+
user = User.first
|
|
53
|
+
Stripper.strip(user) # => #<struct id=2, email="cow@cow.cow", password_hash="...">
|
|
54
|
+
user.email # => "cow@cow.cow"
|
|
55
|
+
|
|
56
|
+
# with datasets
|
|
57
|
+
user = DB[:users].first # or: User.naked.first
|
|
58
|
+
Stripper.strip(user) # => #<struct id=2, email="cow@cow.cow", password_hash="...">
|
|
59
|
+
user.email # => "cow@cow.cow"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Loading associations
|
|
63
|
+
|
|
64
|
+
If you'd like to also use associations on your struct (works only with models):
|
|
65
|
+
|
|
66
|
+
```ruby
|
|
67
|
+
user = User.first
|
|
68
|
+
Stripper.strip(user, with_associations: %w[cookies])
|
|
69
|
+
# => #<struct id=2, ..., cookies=[#<struct ...>, #<struct ...>, #<struct ...>]>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Beware that this will load _all_ cookies associated with your user! If you want to impose some
|
|
73
|
+
filtering conditions, you can do that:
|
|
74
|
+
|
|
75
|
+
```ruby
|
|
76
|
+
user = User.first
|
|
77
|
+
Stripper.strip(
|
|
78
|
+
user,
|
|
79
|
+
with_associations: { cookies: -> (ds) { ds.where(active: true).limit(10) } },
|
|
80
|
+
)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
This will only load no more than 10 active cookies.
|
|
84
|
+
|
|
85
|
+
### Providing extra attributes
|
|
86
|
+
|
|
87
|
+
Sometimes it's useful to provide some context beyond associations and model/dataset attributes.
|
|
88
|
+
|
|
89
|
+
In the example below, we're providing information about user's payment sum, not only user's fields.
|
|
90
|
+
|
|
91
|
+
```ruby
|
|
92
|
+
# with a model
|
|
93
|
+
user = User
|
|
94
|
+
.left_join(:payments)
|
|
95
|
+
.select_all(:users)
|
|
96
|
+
.select_append(
|
|
97
|
+
Sequel.function(:sum, Sequel[:payments][:amount]).as(:payment_sum),
|
|
98
|
+
)
|
|
99
|
+
.group(Sequel[:users][:id])
|
|
100
|
+
.first
|
|
101
|
+
|
|
102
|
+
Stripper.strip(user, with_attributes: { payment_sum: user[:payment_sum] })
|
|
103
|
+
# => #<struct id=2, ..., payment_sum=418.0>
|
|
104
|
+
|
|
105
|
+
# with a dataset, it's nearly identical
|
|
106
|
+
user = DB[:users]
|
|
107
|
+
.left_join(:payments)
|
|
108
|
+
.select_all(:users)
|
|
109
|
+
.select_append(
|
|
110
|
+
Sequel.function(:sum, Sequel[:payments][:amount]).as(:payment_sum),
|
|
111
|
+
)
|
|
112
|
+
.group(Sequel[:users][:id])
|
|
113
|
+
.first
|
|
114
|
+
|
|
115
|
+
Stripper.strip(user, with_attributes: { payment_sum: user[:payment_sum] })
|
|
116
|
+
# => #<struct id=2, ..., payment_sum=418.0>
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Default value conversions
|
|
120
|
+
|
|
121
|
+
`Sequel::Postgres::JSONHashBase` (`JSONBHash`, `JSONHash`, ...) => `Hash`
|
|
122
|
+
|
|
123
|
+
`Sequel::Postgres::JSONArrayBase` (`JSONBArray`, `JSONArray`, ...) => `Array`
|
|
124
|
+
|
|
125
|
+
`Sequel::Postgres::PGArray` => `Array`
|
|
126
|
+
|
|
127
|
+
`BigDecimal` => `Float`
|
|
128
|
+
|
|
129
|
+
Currently, these are not extensible.
|
|
130
|
+
|
|
131
|
+
## Roadmap
|
|
132
|
+
|
|
133
|
+
It would be lovely to:
|
|
134
|
+
- Make value conversions extensible
|
|
135
|
+
- Support ActiveRecord
|
|
136
|
+
- Test the gem on other databases
|
|
137
|
+
|
|
138
|
+
Your contributions and feedback are very welcome!
|
|
139
|
+
|
|
140
|
+
## Development
|
|
141
|
+
|
|
142
|
+
To run tests, you need to first create a PostgreSQL database, and then set a `DB_URL` variable.
|
|
143
|
+
|
|
144
|
+
Example:
|
|
145
|
+
```sh
|
|
146
|
+
DB_URL=postgres://localhost/scripper_test bundle exec rspec
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
If you want to enable Sequel's database access logging during spec runs, use `LOG_DB=1`.
|
|
150
|
+
|
|
151
|
+
## Contributing
|
|
152
|
+
|
|
153
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/umbrellio/scripper.
|
|
154
|
+
|
|
155
|
+
## License
|
|
156
|
+
|
|
157
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
|
158
|
+
|
|
159
|
+
## Authors
|
|
160
|
+
Created by [Alexander Komarov](https://github.com/akxcv).
|
|
161
|
+
|
|
162
|
+
<a href="https://github.com/umbrellio/">
|
|
163
|
+
<img style="float: left;" src="https://umbrellio.github.io/Umbrellio/supported_by_umbrellio.svg" alt="Supported by Umbrellio" width="439" height="72">
|
|
164
|
+
</a>
|
data/Rakefile
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "bundler/gem_tasks"
|
|
4
|
-
require "rspec/core/rake_task"
|
|
5
|
-
|
|
6
|
-
RSpec::Core::RakeTask.new(:spec)
|
|
7
|
-
|
|
8
|
-
task default: :spec
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bundler/gem_tasks"
|
|
4
|
+
require "rspec/core/rake_task"
|
|
5
|
+
|
|
6
|
+
RSpec::Core::RakeTask.new(:spec)
|
|
7
|
+
|
|
8
|
+
task default: :spec
|
data/lib/scripper.rb
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "scripper/sequel"
|
|
4
|
-
require "scripper/sequel/dataset_stripper"
|
|
5
|
-
require "scripper/sequel/model_stripper"
|
|
6
|
-
require "scripper/sequel/value_converter"
|
|
7
|
-
|
|
8
|
-
module Scripper; end
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "scripper/sequel"
|
|
4
|
+
require "scripper/sequel/dataset_stripper"
|
|
5
|
+
require "scripper/sequel/model_stripper"
|
|
6
|
+
require "scripper/sequel/value_converter"
|
|
7
|
+
|
|
8
|
+
module Scripper; end
|
data/lib/scripper/sequel.rb
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Scripper
|
|
4
|
-
module Sequel
|
|
5
|
-
class << self
|
|
6
|
-
def strip(object, **args)
|
|
7
|
-
if object.is_a?(Hash)
|
|
8
|
-
strip_dataset(object)
|
|
9
|
-
else
|
|
10
|
-
strip_model(object, **args)
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
private
|
|
15
|
-
|
|
16
|
-
def strip_model(*args)
|
|
17
|
-
ModelStripper.strip(*args)
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def strip_dataset(ds)
|
|
21
|
-
DatasetStripper.strip(ds)
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Scripper
|
|
4
|
+
module Sequel
|
|
5
|
+
class << self
|
|
6
|
+
def strip(object, **args)
|
|
7
|
+
if object.is_a?(Hash)
|
|
8
|
+
strip_dataset(object)
|
|
9
|
+
else
|
|
10
|
+
strip_model(object, **args)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def strip_model(*args)
|
|
17
|
+
ModelStripper.strip(*args)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def strip_dataset(ds)
|
|
21
|
+
DatasetStripper.strip(ds)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Scripper
|
|
4
|
-
module Sequel
|
|
5
|
-
module DatasetStripper
|
|
6
|
-
class << self
|
|
7
|
-
def strip(hsh)
|
|
8
|
-
struct_klass = Struct.new(*hsh.keys)
|
|
9
|
-
struct_klass.new(*hsh.transform_values { |v| ValueConverter.convert_value(v) }.values)
|
|
10
|
-
end
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Scripper
|
|
4
|
+
module Sequel
|
|
5
|
+
module DatasetStripper
|
|
6
|
+
class << self
|
|
7
|
+
def strip(hsh)
|
|
8
|
+
struct_klass = Struct.new(*hsh.keys)
|
|
9
|
+
struct_klass.new(*hsh.transform_values { |v| ValueConverter.convert_value(v) }.values)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -1,63 +1,69 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Scripper
|
|
4
|
-
module Sequel
|
|
5
|
-
module ModelStripper
|
|
6
|
-
class << self
|
|
7
|
-
def strip(object, with_associations: nil, with_attributes: nil)
|
|
8
|
-
association_fields = build_association_fields(object, with_associations)
|
|
9
|
-
attribute_fields = build_attribute_fields(object, with_attributes)
|
|
10
|
-
|
|
11
|
-
attrs = {
|
|
12
|
-
**convert_values(object.values),
|
|
13
|
-
**association_fields,
|
|
14
|
-
**attribute_fields,
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
struct_klass = Struct.new(*attrs.keys)
|
|
18
|
-
struct_klass.new(*attrs.values)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
private
|
|
22
|
-
|
|
23
|
-
def build_association_fields(object, associations)
|
|
24
|
-
return {} if associations.nil?
|
|
25
|
-
|
|
26
|
-
if associations.is_a?(Array)
|
|
27
|
-
build_association_fields_from_array(object, associations)
|
|
28
|
-
else # consider associations a hash
|
|
29
|
-
build_association_fields_from_hash(object, associations)
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def build_attribute_fields(object, attributes)
|
|
34
|
-
return {} if attributes.nil?
|
|
35
|
-
|
|
36
|
-
convert_values(attributes)
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def convert_values(hsh)
|
|
40
|
-
hsh.transform_values { |v| ValueConverter.convert_value(v) }
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def build_association_fields_from_array(object, associations)
|
|
44
|
-
associations.reduce({}) do |acc, association|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Scripper
|
|
4
|
+
module Sequel
|
|
5
|
+
module ModelStripper
|
|
6
|
+
class << self
|
|
7
|
+
def strip(object, with_associations: nil, with_attributes: nil)
|
|
8
|
+
association_fields = build_association_fields(object, with_associations)
|
|
9
|
+
attribute_fields = build_attribute_fields(object, with_attributes)
|
|
10
|
+
|
|
11
|
+
attrs = {
|
|
12
|
+
**convert_values(object.values),
|
|
13
|
+
**association_fields,
|
|
14
|
+
**attribute_fields,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
struct_klass = Struct.new(*attrs.keys)
|
|
18
|
+
struct_klass.new(*attrs.values)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def build_association_fields(object, associations)
|
|
24
|
+
return {} if associations.nil?
|
|
25
|
+
|
|
26
|
+
if associations.is_a?(Array)
|
|
27
|
+
build_association_fields_from_array(object, associations)
|
|
28
|
+
else # consider associations a hash
|
|
29
|
+
build_association_fields_from_hash(object, associations)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def build_attribute_fields(object, attributes)
|
|
34
|
+
return {} if attributes.nil?
|
|
35
|
+
|
|
36
|
+
convert_values(attributes)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def convert_values(hsh)
|
|
40
|
+
hsh.transform_values { |v| ValueConverter.convert_value(v) }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def build_association_fields_from_array(object, associations)
|
|
44
|
+
associations.reduce({}) do |acc, association|
|
|
45
|
+
association_value = object.public_send(association)
|
|
46
|
+
stripped_association_value =
|
|
47
|
+
if association_value.is_a?(Array)
|
|
48
|
+
association_value.map { |obj| strip(obj) }
|
|
49
|
+
else
|
|
50
|
+
strip(association_value)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
acc.merge(association.to_sym => stripped_association_value)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def build_association_fields_from_hash(object, associations)
|
|
58
|
+
associations.entries.reduce({}) do |acc, (association, condition)|
|
|
59
|
+
association_ds = object.class.association_reflection(association).associated_dataset
|
|
60
|
+
|
|
61
|
+
acc.merge(
|
|
62
|
+
association.to_sym => condition.call(association_ds).all.map { |obj| strip(obj) },
|
|
63
|
+
)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Scripper
|
|
4
|
-
module Sequel
|
|
5
|
-
module ValueConverter
|
|
6
|
-
class << self
|
|
7
|
-
def convert_value(value)
|
|
8
|
-
if value.is_a?(::Sequel::Postgres::JSONHashBase)
|
|
9
|
-
value.to_h
|
|
10
|
-
elsif value.is_a?(::Sequel::Postgres::JSONArrayBase)
|
|
11
|
-
value.to_a
|
|
12
|
-
elsif value.is_a?(::Sequel::Postgres::PGArray)
|
|
13
|
-
value.to_a
|
|
14
|
-
elsif value.is_a?(BigDecimal)
|
|
15
|
-
value.to_f
|
|
16
|
-
else
|
|
17
|
-
value
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Scripper
|
|
4
|
+
module Sequel
|
|
5
|
+
module ValueConverter
|
|
6
|
+
class << self
|
|
7
|
+
def convert_value(value)
|
|
8
|
+
if value.is_a?(::Sequel::Postgres::JSONHashBase)
|
|
9
|
+
value.to_h
|
|
10
|
+
elsif value.is_a?(::Sequel::Postgres::JSONArrayBase)
|
|
11
|
+
value.to_a
|
|
12
|
+
elsif value.is_a?(::Sequel::Postgres::PGArray)
|
|
13
|
+
value.to_a
|
|
14
|
+
elsif value.is_a?(BigDecimal)
|
|
15
|
+
value.to_f
|
|
16
|
+
else
|
|
17
|
+
value
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
data/scripper.gemspec
CHANGED
|
@@ -1,35 +1,35 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
lib = File.expand_path(
|
|
4
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
5
|
-
|
|
6
|
-
Gem::Specification.new do |spec|
|
|
7
|
-
spec.name =
|
|
8
|
-
spec.version =
|
|
9
|
-
spec.authors = [
|
|
10
|
-
spec.email = [
|
|
11
|
-
|
|
12
|
-
spec.summary =
|
|
13
|
-
spec.description =
|
|
14
|
-
spec.homepage =
|
|
15
|
-
spec.license =
|
|
16
|
-
|
|
17
|
-
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
|
18
|
-
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
19
|
-
end
|
|
20
|
-
spec.bindir =
|
|
21
|
-
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
22
|
-
spec.require_paths = [
|
|
23
|
-
|
|
24
|
-
spec.add_development_dependency
|
|
25
|
-
spec.add_development_dependency
|
|
26
|
-
spec.add_development_dependency
|
|
27
|
-
spec.add_development_dependency
|
|
28
|
-
spec.add_development_dependency
|
|
29
|
-
spec.add_development_dependency
|
|
30
|
-
spec.add_development_dependency
|
|
31
|
-
spec.add_development_dependency
|
|
32
|
-
|
|
33
|
-
spec.add_development_dependency
|
|
34
|
-
spec.add_development_dependency
|
|
35
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
lib = File.expand_path("lib", __dir__)
|
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = "scripper"
|
|
8
|
+
spec.version = "0.1.1"
|
|
9
|
+
spec.authors = ["Alexander Komarov <ak@akxcv.com>"]
|
|
10
|
+
spec.email = %w[ak@akxcv.com]
|
|
11
|
+
|
|
12
|
+
spec.summary = "A gem that strips Sequel models down to simple value objects"
|
|
13
|
+
spec.description = "@see summary"
|
|
14
|
+
spec.homepage = "https://github.com/umbrellio/scripper"
|
|
15
|
+
spec.license = "MIT"
|
|
16
|
+
|
|
17
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
|
18
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
19
|
+
end
|
|
20
|
+
spec.bindir = "exe"
|
|
21
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
22
|
+
spec.require_paths = %w[lib]
|
|
23
|
+
|
|
24
|
+
spec.add_development_dependency "bundler", "~> 2.0"
|
|
25
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
|
26
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
|
27
|
+
spec.add_development_dependency "simplecov"
|
|
28
|
+
spec.add_development_dependency "coveralls"
|
|
29
|
+
spec.add_development_dependency "armitage-rubocop"
|
|
30
|
+
spec.add_development_dependency "rubocop-config-umbrellio"
|
|
31
|
+
spec.add_development_dependency "pry"
|
|
32
|
+
|
|
33
|
+
spec.add_development_dependency "pg"
|
|
34
|
+
spec.add_development_dependency "sequel"
|
|
35
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: scripper
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alexander Komarov <ak@akxcv.com>
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2019-10-
|
|
11
|
+
date: 2019-10-14 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -162,7 +162,6 @@ files:
|
|
|
162
162
|
- ".rubocop.yml"
|
|
163
163
|
- ".travis.yml"
|
|
164
164
|
- Gemfile
|
|
165
|
-
- Gemfile.lock
|
|
166
165
|
- LICENSE
|
|
167
166
|
- README.md
|
|
168
167
|
- Rakefile
|
data/Gemfile.lock
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
PATH
|
|
2
|
-
remote: .
|
|
3
|
-
specs:
|
|
4
|
-
scripper (0.1.0)
|
|
5
|
-
|
|
6
|
-
GEM
|
|
7
|
-
remote: https://rubygems.org/
|
|
8
|
-
specs:
|
|
9
|
-
armitage-rubocop (0.70.0.110)
|
|
10
|
-
rubocop (= 0.70.0)
|
|
11
|
-
rubocop-performance (= 1.3.0)
|
|
12
|
-
rubocop-rails (= 2.0.0)
|
|
13
|
-
rubocop-rspec (= 1.33.0)
|
|
14
|
-
ast (2.4.0)
|
|
15
|
-
coderay (1.1.2)
|
|
16
|
-
coveralls (0.7.2)
|
|
17
|
-
multi_json (~> 1.3)
|
|
18
|
-
rest-client (= 1.6.7)
|
|
19
|
-
simplecov (>= 0.7)
|
|
20
|
-
term-ansicolor (= 1.2.2)
|
|
21
|
-
thor (= 0.18.1)
|
|
22
|
-
diff-lcs (1.3)
|
|
23
|
-
docile (1.3.2)
|
|
24
|
-
jaro_winkler (1.5.3)
|
|
25
|
-
json (2.2.0)
|
|
26
|
-
method_source (0.9.2)
|
|
27
|
-
mime-types (3.3)
|
|
28
|
-
mime-types-data (~> 3.2015)
|
|
29
|
-
mime-types-data (3.2019.1009)
|
|
30
|
-
multi_json (1.13.1)
|
|
31
|
-
parallel (1.18.0)
|
|
32
|
-
parser (2.6.5.0)
|
|
33
|
-
ast (~> 2.4.0)
|
|
34
|
-
pg (1.1.4-x64-mingw32)
|
|
35
|
-
pry (0.12.2)
|
|
36
|
-
coderay (~> 1.1.0)
|
|
37
|
-
method_source (~> 0.9.0)
|
|
38
|
-
rack (2.0.7)
|
|
39
|
-
rainbow (3.0.0)
|
|
40
|
-
rake (10.5.0)
|
|
41
|
-
rest-client (1.6.7)
|
|
42
|
-
mime-types (>= 1.16)
|
|
43
|
-
rspec (3.9.0)
|
|
44
|
-
rspec-core (~> 3.9.0)
|
|
45
|
-
rspec-expectations (~> 3.9.0)
|
|
46
|
-
rspec-mocks (~> 3.9.0)
|
|
47
|
-
rspec-core (3.9.0)
|
|
48
|
-
rspec-support (~> 3.9.0)
|
|
49
|
-
rspec-expectations (3.9.0)
|
|
50
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
|
51
|
-
rspec-support (~> 3.9.0)
|
|
52
|
-
rspec-mocks (3.9.0)
|
|
53
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
|
54
|
-
rspec-support (~> 3.9.0)
|
|
55
|
-
rspec-support (3.9.0)
|
|
56
|
-
rubocop (0.70.0)
|
|
57
|
-
jaro_winkler (~> 1.5.1)
|
|
58
|
-
parallel (~> 1.10)
|
|
59
|
-
parser (>= 2.6)
|
|
60
|
-
rainbow (>= 2.2.2, < 4.0)
|
|
61
|
-
ruby-progressbar (~> 1.7)
|
|
62
|
-
unicode-display_width (>= 1.4.0, < 1.7)
|
|
63
|
-
rubocop-config-umbrellio (0.70.0.55)
|
|
64
|
-
rubocop (= 0.70.0)
|
|
65
|
-
rubocop-performance (= 1.3.0)
|
|
66
|
-
rubocop-rspec (= 1.33.0)
|
|
67
|
-
rubocop-performance (1.3.0)
|
|
68
|
-
rubocop (>= 0.68.0)
|
|
69
|
-
rubocop-rails (2.0.0)
|
|
70
|
-
rack (>= 2.0)
|
|
71
|
-
rubocop (>= 0.70.0)
|
|
72
|
-
rubocop-rspec (1.33.0)
|
|
73
|
-
rubocop (>= 0.60.0)
|
|
74
|
-
ruby-progressbar (1.10.1)
|
|
75
|
-
sequel (5.25.0)
|
|
76
|
-
simplecov (0.17.1)
|
|
77
|
-
docile (~> 1.1)
|
|
78
|
-
json (>= 1.8, < 3)
|
|
79
|
-
simplecov-html (~> 0.10.0)
|
|
80
|
-
simplecov-html (0.10.2)
|
|
81
|
-
term-ansicolor (1.2.2)
|
|
82
|
-
tins (~> 0.8)
|
|
83
|
-
thor (0.18.1)
|
|
84
|
-
tins (0.13.2)
|
|
85
|
-
unicode-display_width (1.6.0)
|
|
86
|
-
|
|
87
|
-
PLATFORMS
|
|
88
|
-
x64-mingw32
|
|
89
|
-
|
|
90
|
-
DEPENDENCIES
|
|
91
|
-
armitage-rubocop
|
|
92
|
-
bundler (~> 2.0)
|
|
93
|
-
coveralls
|
|
94
|
-
pg
|
|
95
|
-
pry
|
|
96
|
-
rake (~> 10.0)
|
|
97
|
-
rspec (~> 3.0)
|
|
98
|
-
rubocop-config-umbrellio
|
|
99
|
-
scripper!
|
|
100
|
-
sequel
|
|
101
|
-
simplecov
|
|
102
|
-
|
|
103
|
-
BUNDLED WITH
|
|
104
|
-
2.0.2
|