rails_readonly_injector 0.2.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/ISSUE_TEMPLATE.md +18 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +24 -0
- data/.gitignore +1 -1
- data/.rubocop.yml +7 -0
- data/.travis.yml +3 -1
- data/Appraisals +10 -1
- data/CHANGELOG.md +6 -0
- data/CODE_OF_CONDUCT.md +0 -0
- data/Gemfile +4 -2
- data/LICENSE.txt +0 -0
- data/README.md +25 -6
- data/Rakefile +4 -2
- data/bin/console +4 -3
- data/cucumber_features/configuration.feature +0 -0
- data/cucumber_features/step_definitions/.gitkeep +0 -0
- data/cucumber_features/step_definitions/generic_steps.rb +5 -3
- data/cucumber_features/step_definitions/user_steps.rb +18 -14
- data/cucumber_features/support/.gitkeep +0 -0
- data/cucumber_features/user_controller.feature +0 -0
- data/cucumber_features/user_controller_readonly.feature +0 -0
- data/cucumber_features/user_model.feature +0 -0
- data/cucumber_features/user_model_readonly.feature +0 -0
- data/development_tasks/support/file_helpers.rb +57 -0
- data/development_tasks/support/gem_helpers.rb +63 -0
- data/development_tasks/tests.rake +40 -93
- data/gemfiles/.bundle/config +0 -0
- data/gemfiles/rails_3.gemfile +0 -0
- data/gemfiles/rails_4_0.gemfile +0 -0
- data/gemfiles/rails_4_1.gemfile +0 -0
- data/gemfiles/rails_4_2.gemfile +0 -0
- data/gemfiles/rails_5_0.gemfile +0 -0
- data/gemfiles/rails_5_1.gemfile +0 -0
- data/gemfiles/rails_5_2.gemfile +10 -0
- data/lib/rails_readonly_injector.rb +37 -20
- data/lib/rails_readonly_injector/configuration.rb +86 -20
- data/lib/rails_readonly_injector/version.rb +3 -1
- data/rails_readonly_injector.gemspec +16 -14
- data/rspec_specs/.gitkeep +0 -0
- data/rspec_specs/rails_readonly_injector/configuration_spec.rb +167 -0
- data/rspec_specs/{readonly_site_toggle_spec.rb → rails_readonly_injector_spec.rb} +42 -1
- data/rspec_specs/support/.gitkeep +0 -0
- metadata +36 -18
- data/rspec_specs/readonly_site_toggle/configuration_spec.rb +0 -31
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: b312c92be7dd7bf454f93b2359d6615eac31e5db380c10823da084b1a012c43f
|
4
|
+
data.tar.gz: 82fd6c6929b64104bf7d68044e5c13557bf798cedaad996a5495234c99d08366
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5ebe26220df8db19da6ddf8623b5fb7f3d09a3c192eac5ffec3794106b9008126cbb4276f222027e6e4bfbfa1871f3abbd7da2f7356267a77a9e57760a677a5c
|
7
|
+
data.tar.gz: 476aa9f4c712902fac248b7b185a931b13d056f4414b5b483842087c19ddc7116118ddece04f3a86f41f579f2af1efe5826bce525f3846c60e2a851cf9bc680d
|
@@ -0,0 +1,24 @@
|
|
1
|
+
## Problem
|
2
|
+
|
3
|
+
<!-- Describe the problem that this PR resolves -->
|
4
|
+
|
5
|
+
#### Related issues:
|
6
|
+
<!-- Link to issues that are related to this problem. If there aren't any, you can remove the heading. -->
|
7
|
+
|
8
|
+
## How this PR resolves the problem
|
9
|
+
|
10
|
+
<!--- Describe how your PR resolves this problem -->
|
11
|
+
|
12
|
+
## Types of changes
|
13
|
+
|
14
|
+
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
|
15
|
+
- [ ] Bug fix (non-breaking change which fixes an issue).
|
16
|
+
- [ ] New feature (non-breaking change which adds functionality).
|
17
|
+
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected).
|
18
|
+
|
19
|
+
## Checklist:
|
20
|
+
|
21
|
+
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
|
22
|
+
- [ ] I've added tests for my code.
|
23
|
+
- [ ] My change requires a change to the documentation.
|
24
|
+
- [ ] I have updated the documentation accordingly.
|
data/.gitignore
CHANGED
data/.rubocop.yml
ADDED
data/.travis.yml
CHANGED
@@ -13,7 +13,6 @@ branches:
|
|
13
13
|
only:
|
14
14
|
- master
|
15
15
|
|
16
|
-
|
17
16
|
before_script:
|
18
17
|
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
19
18
|
- chmod +x ./cc-test-reporter
|
@@ -29,6 +28,7 @@ gemfile:
|
|
29
28
|
- gemfiles/rails_4_2.gemfile
|
30
29
|
- gemfiles/rails_5_0.gemfile
|
31
30
|
- gemfiles/rails_5_1.gemfile
|
31
|
+
- gemfiles/rails_5_2.gemfile
|
32
32
|
|
33
33
|
matrix:
|
34
34
|
fast_finish: true
|
@@ -41,6 +41,8 @@ matrix:
|
|
41
41
|
gemfile: gemfiles/rails_5_0.gemfile
|
42
42
|
- rvm: 2.1.3
|
43
43
|
gemfile: gemfiles/rails_5_1.gemfile
|
44
|
+
- rvm: 2.1.3
|
45
|
+
gemfile: gemfiles/rails_5_2.gemfile
|
44
46
|
- rvm: 2.2.7
|
45
47
|
gemfile: gemfiles/rails_3.gemfile
|
46
48
|
- rvm: 2.3.6
|
data/Appraisals
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
appraise 'rails_3' do
|
2
4
|
gem 'rails', '~> 3'
|
3
5
|
gem 'cucumber-rails', '~> 1.4.5'
|
@@ -43,4 +45,11 @@ appraise 'rails_5_1' do
|
|
43
45
|
gem 'cucumber-rails', '~> 1.5.0', group: :test, require: false
|
44
46
|
gem 'rspec-rails', '~> 3.7.2', group: :test
|
45
47
|
gem 'database_cleaner', '~> 1.0.1'
|
46
|
-
end
|
48
|
+
end
|
49
|
+
|
50
|
+
appraise 'rails_5_2' do
|
51
|
+
gem 'rails', '~> 5.2.0'
|
52
|
+
gem 'cucumber-rails', '~> 1.6.0', group: :test, require: false
|
53
|
+
gem 'rspec-rails', '~> 3.7.2', group: :test
|
54
|
+
gem 'database_cleaner', '~> 1.0.1'
|
55
|
+
end
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
## 1.0.1
|
2
|
+
- Added support for Rails 5.2
|
3
|
+
## 1.0.0
|
4
|
+
- Removed the ability to read the current read-only status using `RailsReadonlyInjector.config.read_only`, and replaced it with `RailsReadonlyInjector.in_read_only_mode?`.
|
5
|
+
## 0.3.0
|
6
|
+
- Added ability to explicitly include specific classes.
|
1
7
|
## 0.2.0
|
2
8
|
- Added ability to exclude specific classes from read-only mode.
|
3
9
|
- Improved support for Rails 5 (Automatic inclusion of descendants of `ApplicationRecord` rather than `ActiveRecord::Base`).
|
data/CODE_OF_CONDUCT.md
CHANGED
File without changes
|
data/Gemfile
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
source 'https://rubygems.org'
|
4
|
+
|
5
|
+
git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
|
4
6
|
|
5
7
|
# Specify your gem's dependencies in rails_readonly_injector.gemspec
|
6
8
|
gemspec
|
data/LICENSE.txt
CHANGED
File without changes
|
data/README.md
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# Rails ReadOnly Injector
|
2
2
|
[![Build Status](https://travis-ci.org/xtrasimplicity/rails_readonly_injector.svg?branch=master)](https://travis-ci.org/xtrasimplicity/rails_readonly_injector)
|
3
|
+
[![Read the Docs](https://img.shields.io/readthedocs/pip.svg)](http://www.rubydoc.info/github/xtrasimplicity/rails_readonly_injector/master)
|
3
4
|
[![Maintainability](https://api.codeclimate.com/v1/badges/427c153efd48ae03f688/maintainability)](https://codeclimate.com/github/xtrasimplicity/rails_readonly_injector/maintainability)
|
4
5
|
[![Test Coverage](https://api.codeclimate.com/v1/badges/427c153efd48ae03f688/test_coverage)](https://codeclimate.com/github/xtrasimplicity/rails_readonly_injector/test_coverage)
|
5
6
|
[![Gem Version](https://badge.fury.io/rb/rails_readonly_injector.svg)](https://badge.fury.io/rb/rails_readonly_injector)
|
@@ -24,14 +25,16 @@ Or install it yourself as:
|
|
24
25
|
|
25
26
|
## Usage
|
26
27
|
|
27
|
-
In order to switch a complete site into read-only mode, you will first need to set the action to occur when an attempt to commit changes to the database is made, from within a controller.
|
28
|
+
In order to switch a complete site into read-only mode, you will first need to set the action to occur when an attempt to commit changes to the database is made, from within a controller. This action will be executed from within the context of the referring controller.
|
29
|
+
|
30
|
+
Usually, this won't need to change once the application has booted, so I recommend defining it within an initializer, as follows:
|
28
31
|
|
29
32
|
```
|
30
33
|
# config/initializers/rails_readonly_injector.rb
|
31
34
|
RailsReadonlyInjector.config do |config|
|
32
35
|
config.controller_rescue_action = lambda do |context|
|
33
36
|
# Define actions to be performed if changes to a read-only model are attempted to be committed to the database.
|
34
|
-
# This lambda expression is evaluated from within the
|
37
|
+
# This lambda expression is evaluated from within the context of the referring controller.
|
35
38
|
|
36
39
|
# You may want to set a redirect, or flash an error message, or something, here.
|
37
40
|
# e.g.
|
@@ -41,21 +44,37 @@ RailsReadonlyInjector.config do |config|
|
|
41
44
|
end
|
42
45
|
```
|
43
46
|
|
44
|
-
When you want to switch a site into read-only mode, you can then simply
|
47
|
+
When you want to switch a site into read-only mode, you can then simply
|
48
|
+
* set `RailsReadOnlyInjector.config.read_only` to true, and then
|
49
|
+
* call `RailsReadonlyInjector.reload!` to (re-)load the configuration.
|
50
|
+
|
51
|
+
Alternatively, you can also set `read_only` from within the configuration block inside the initializer.
|
45
52
|
|
46
53
|
If you want to reset the configuration to the defaults, you can simply call `RailsReadonlyInjector.reset_configuration!` from anywhere in your application.
|
47
54
|
|
55
|
+
If you want to check whether read-only mode is currently enabled, you can use `RailsReadonlyInjector.in_read_only_mode?`.
|
56
|
+
|
48
57
|
## Configuration Options
|
58
|
+
The following configuration options can be set through `RailsReadonlyInjector.config`:
|
59
|
+
|
49
60
|
- `read_only` => Whether the site should be in read-only mode. (Default: false)
|
50
|
-
- `
|
61
|
+
- `classes_to_exclude` => An array of classes that should be _exempt_ from read-only mode. (Default: `[]`)
|
62
|
+
- `classes_to_include` => An array of classes that should be set to read-only mode. (Defaults to `ActiveRecord::Base.descendants` on Rails 3-4, and `ApplicationRecord.descendants` on Rails 5.0+)
|
51
63
|
- `controller_rescue_action` => A lambda expression/Proc to execute when an `ActiveRecord::ReadOnlyRecord` error is raised, from within a controller.
|
64
|
+
|
52
65
|
## Development
|
53
66
|
|
54
67
|
After checking out the repo, run `bundle install` to install the dependencies.
|
55
68
|
|
56
|
-
RSpec specs and Cucumber features are stored in `rspec_specs` and `cucumber_features`, respectively. When `bundle exec rake` is run against an appraisal, the contents of these folders are copied to the necessary folders under the temporary rails application that
|
69
|
+
RSpec specs and Cucumber features are stored in `rspec_specs` and `cucumber_features`, respectively. When `bundle exec rake` is run against an appraisal, the contents of these folders are copied to the necessary folders under the temporary rails application that `bundle exec rake` generates into `tmp/rails_app`.
|
70
|
+
|
71
|
+
To run tests for a specific version of Rails, simply run `bundle exec appraisal {APPRAISAL} bundle exec rake`, where `{APPRAISAL}` is one of the appraisals found under `Appraisals`. e.g. `bundle exec appraisal rails_4_1 bundle exec rake`
|
72
|
+
|
73
|
+
If you don't want to re-build the temporary application each time you run tests, you can execute the following rake tasks against an appraisal:
|
57
74
|
|
58
|
-
|
75
|
+
* `dev:run_features` => Synchronises features from `cucumber_features` into the temporary rails application, and runs cucumber against the temporary application.
|
76
|
+
* `dev:run_specs` => Synchronises specs from `rspec_specs` into the temporary rails application, and runs rspec against the temporary application.
|
77
|
+
* `dev:run_tests` => Runs both `dev:run_features` and `dev:run_specs`, and ret on failure.
|
59
78
|
|
60
79
|
## Contributing
|
61
80
|
|
data/Rakefile
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/gem_tasks'
|
2
4
|
|
3
5
|
development_tasks_path = File.expand_path('../development_tasks', __FILE__)
|
4
6
|
|
5
7
|
Dir[File.join(development_tasks_path, '*.rake')].each { |rb| load rb }
|
6
8
|
|
7
|
-
task :
|
9
|
+
task default: ['dev:deploy_test_app', 'dev:run_tests']
|
data/bin/console
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
|
-
require
|
4
|
-
require
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'rails_readonly_injector'
|
5
6
|
|
6
7
|
# You can add fixtures and/or initialization code here to make experimenting
|
7
8
|
# with your gem easier. You can also use a different console, if you like.
|
@@ -10,5 +11,5 @@ require "rails_readonly_injector"
|
|
10
11
|
# require "pry"
|
11
12
|
# Pry.start
|
12
13
|
|
13
|
-
require
|
14
|
+
require 'irb'
|
14
15
|
IRB.start(__FILE__)
|
File without changes
|
File without changes
|
@@ -1,7 +1,9 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Given('I execute:') do |code|
|
2
4
|
eval code
|
3
5
|
end
|
4
6
|
|
5
|
-
Then(
|
7
|
+
Then('The page should contain {string}') do |string|
|
6
8
|
expect(page).to have_content(string)
|
7
|
-
end
|
9
|
+
end
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Given('There is a user that has been persisted to the database') do
|
2
4
|
RailsReadonlyInjector.config.read_only = false
|
3
5
|
RailsReadonlyInjector.reload!
|
4
6
|
|
@@ -7,43 +9,45 @@ Given("There is a user that has been persisted to the database") do
|
|
7
9
|
expect(@user.persisted?).to eq(true)
|
8
10
|
end
|
9
11
|
|
10
|
-
Given(
|
12
|
+
Given('There is a user that has not been persisted to the database') do
|
11
13
|
User.destroy_all
|
12
|
-
|
14
|
+
|
13
15
|
@user = User.new(name: 'Bob')
|
14
16
|
end
|
15
17
|
|
16
|
-
When(
|
18
|
+
When('I update the user') do
|
17
19
|
begin
|
18
20
|
@user.update_attributes(name: 'Fred')
|
19
21
|
rescue ActiveRecord::ReadOnlyRecord
|
20
22
|
end
|
21
23
|
end
|
22
24
|
|
23
|
-
When(
|
25
|
+
When('I save the user') do
|
24
26
|
begin
|
25
27
|
@user.save
|
26
28
|
rescue ActiveRecord::ReadOnlyRecord
|
27
29
|
end
|
28
30
|
end
|
29
31
|
|
30
|
-
Then(
|
32
|
+
Then('the user should not be updated') do
|
31
33
|
@user.reload
|
32
|
-
|
34
|
+
|
33
35
|
expect(@user.name).to eq('Bob')
|
34
36
|
end
|
35
37
|
|
36
|
-
Then(
|
38
|
+
Then('the user should be updated') do
|
37
39
|
@user.reload
|
38
40
|
|
39
41
|
expect(@user.name).to eq('Fred')
|
40
42
|
end
|
41
43
|
|
42
|
-
Then(
|
44
|
+
Then('the user should be saved') do
|
45
|
+
@user.reload
|
46
|
+
|
43
47
|
expect(@user.persisted?).to eq(true)
|
44
48
|
end
|
45
49
|
|
46
|
-
Then(
|
50
|
+
Then('the user should not be saved') do
|
47
51
|
expect(User.all.length).to eq(0)
|
48
52
|
end
|
49
53
|
|
@@ -54,15 +58,15 @@ When("I'm using a web browser and attempt to update the user") do
|
|
54
58
|
end
|
55
59
|
|
56
60
|
When("I'm using a web browser and attempt to create a user") do
|
57
|
-
visit
|
61
|
+
visit '/users/new'
|
58
62
|
fill_in 'user[name]', with: 'Fred'
|
59
63
|
click_on 'Create User'
|
60
64
|
end
|
61
65
|
|
62
|
-
Then(
|
66
|
+
Then('the user should be created') do
|
63
67
|
expect(User.all.length).to eq(1)
|
64
68
|
end
|
65
69
|
|
66
|
-
Then(
|
70
|
+
Then('I should be able to create a user without any errors') do
|
67
71
|
expect { User.create(name: 'Bob') }.not_to raise_error
|
68
|
-
end
|
72
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
# :nodoc:
|
6
|
+
module FileHelpers
|
7
|
+
GEM_ROOT_PATH = File.expand_path('../../..', __FILE__).freeze
|
8
|
+
RAILS_APP_PATH = File.expand_path(File.join(GEM_ROOT_PATH, 'tmp', 'rails_app')).freeze
|
9
|
+
|
10
|
+
def append_to_file(path_to_file, content)
|
11
|
+
raise 'The specified path is not a file!' unless File.file? path_to_file
|
12
|
+
|
13
|
+
File.open(path_to_file, 'a') do |f|
|
14
|
+
f.write content
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def append_to_beginning_of_file(path_to_file, content)
|
19
|
+
raise 'The specified path is not a file!' unless File.file? path_to_file
|
20
|
+
|
21
|
+
existing_content_as_array = File.open(path_to_file, 'r').readlines
|
22
|
+
|
23
|
+
new_content_arr = [content] + existing_content_as_array
|
24
|
+
|
25
|
+
write_file_with_content path_to_file, new_content_arr.join("\n")
|
26
|
+
end
|
27
|
+
|
28
|
+
def write_file_with_content(path_to_file, content)
|
29
|
+
File.open(path_to_file, 'w') do |f|
|
30
|
+
f.write content
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def switch_to_gems_root_path
|
35
|
+
FileUtils.cd GEM_ROOT_PATH
|
36
|
+
end
|
37
|
+
|
38
|
+
def switch_to_rails_app_path
|
39
|
+
FileUtils.cd RAILS_APP_PATH
|
40
|
+
end
|
41
|
+
|
42
|
+
def generate_rails_application
|
43
|
+
# Remove the app, if it exists already
|
44
|
+
system("rm -rf #{RAILS_APP_PATH}")
|
45
|
+
|
46
|
+
FileUtils.mkdir_p RAILS_APP_PATH
|
47
|
+
system("bundle exec rails new #{RAILS_APP_PATH}")
|
48
|
+
end
|
49
|
+
|
50
|
+
def gems_root_path
|
51
|
+
GEM_ROOT_PATH
|
52
|
+
end
|
53
|
+
|
54
|
+
def rails_app_path
|
55
|
+
RAILS_APP_PATH
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GemHelpers
|
4
|
+
def add_gem(name, attributes = {})
|
5
|
+
line = if attributes.empty?
|
6
|
+
"gem '#{name}'"
|
7
|
+
else
|
8
|
+
"gem '#{name}', #{attributes}"
|
9
|
+
end
|
10
|
+
|
11
|
+
append_to_file('Gemfile', "#{line}\n")
|
12
|
+
end
|
13
|
+
|
14
|
+
# 'Override'/force a specific gem version, as defined in the Appraisal.
|
15
|
+
def ensure_gem_versions_defined_in_appraisal_are_used
|
16
|
+
gems_defined_in_appraisal = retrieve_gems_from_gemfile(ENV['BUNDLE_GEMFILE'])
|
17
|
+
gems_defined_in_gemfile = retrieve_gems_from_gemfile('Gemfile').collect(&:gem_name)
|
18
|
+
|
19
|
+
gems_defined_in_appraisal.reject { |l| gems_defined_in_gemfile.include? l.gem_name }.each do |gem|
|
20
|
+
add_gem gem.gem_name, gem.attributes.join(',')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def install_simplecov(coverage_dir)
|
25
|
+
append_to_beginning_of_file 'spec/spec_helper.rb', %(
|
26
|
+
require 'simplecov'
|
27
|
+
require 'rails_readonly_injector'
|
28
|
+
)
|
29
|
+
append_to_beginning_of_file 'features/support/env.rb', "require 'simplecov'"
|
30
|
+
|
31
|
+
write_file_with_content '.simplecov', %(
|
32
|
+
SimpleCov.start do
|
33
|
+
coverage_dir '#{coverage_dir}'
|
34
|
+
end
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
def unset_appraisal_environment_variables
|
39
|
+
ENV.delete('BUNDLE_GEMFILE')
|
40
|
+
ENV.delete('BUNDLE_BIN_PATH')
|
41
|
+
ENV.delete('RUBYOPT')
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def retrieve_gems_from_gemfile(file_path)
|
47
|
+
gems = []
|
48
|
+
|
49
|
+
File.open(file_path).readlines.each do |line|
|
50
|
+
matches = line.match(/^\s*gem\s+['|"]/)
|
51
|
+
|
52
|
+
next if matches.nil?
|
53
|
+
|
54
|
+
parts = line.split(',')
|
55
|
+
|
56
|
+
gem_name = parts.first.gsub(/\s*gem\s*|["|']|\n/, '')
|
57
|
+
|
58
|
+
gems << OpenStruct.new(gem_name: gem_name, attributes: parts.drop(1))
|
59
|
+
end
|
60
|
+
|
61
|
+
gems
|
62
|
+
end
|
63
|
+
end
|