marty 5.2.0 → 6.1.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.
- checksums.yaml +4 -4
- data/.gitlab-ci.yml +1 -1
- data/.rubocop_todo.yml +62 -77
- data/Dockerfile.dummy +1 -1
- data/app/assets/javascripts/marty/extjs/extensions/marty.js +11 -0
- data/app/components/marty/log_view.rb +1 -1
- data/app/components/marty/promise_view.rb +0 -3
- data/app/jobs/marty/remove_old_promises_job.rb +7 -0
- data/app/models/marty/data_grid.rb +0 -163
- data/app/models/marty/event.rb +2 -2
- data/app/models/marty/posting.rb +0 -7
- data/app/models/marty/promise.rb +1 -1
- data/app/services/marty/data_grid_view/save_grid.rb +2 -2
- data/app/services/marty/jobs/schedule.rb +5 -0
- data/db/migrate/510_schedule_job_to_remove_old_promises.rb +19 -0
- data/lib/marty.rb +8 -0
- data/{other → lib}/marty/api/base.rb +14 -17
- data/{other → lib}/marty/diagnostic/aws/ec2_instance.rb +2 -2
- data/{other → lib}/marty/diagnostic/aws/error.rb +0 -0
- data/{other → lib}/marty/diagnostic/base.rb +0 -0
- data/{other → lib}/marty/diagnostic/collection.rb +0 -0
- data/{other → lib}/marty/diagnostic/connections.rb +0 -0
- data/{other → lib}/marty/diagnostic/database.rb +0 -0
- data/{other → lib}/marty/diagnostic/delayed_job_version.rb +0 -0
- data/{other → lib}/marty/diagnostic/delayed_job_workers.rb +0 -0
- data/{other → lib}/marty/diagnostic/environment_variables.rb +0 -0
- data/{other → lib}/marty/diagnostic/fatal.rb +0 -0
- data/{other → lib}/marty/diagnostic/node.rb +0 -0
- data/{other → lib}/marty/diagnostic/nodes.rb +1 -2
- data/{other → lib}/marty/diagnostic/packer.rb +0 -0
- data/{other → lib}/marty/diagnostic/reporter.rb +2 -2
- data/{other → lib}/marty/diagnostic/request.rb +0 -0
- data/{other → lib}/marty/diagnostic/scheduled_jobs.rb +0 -0
- data/{other → lib}/marty/diagnostic/version.rb +0 -0
- data/lib/marty/engine.rb +5 -0
- data/lib/marty/version.rb +3 -1
- data/lib/marty/xl.rb +5 -5
- data/spec/dummy/app/assets/config/manifest.js +0 -0
- data/spec/dummy/app/jobs/test2_job.rb +4 -0
- data/spec/dummy/config/application.rb +1 -4
- data/spec/dummy/config/initializers/assets.rb +1 -1
- data/spec/features/extjs_spec.rb +58 -0
- data/spec/features/schedule_jobs_dashboard_spec.rb +9 -9
- data/spec/lib/logger_spec.rb +2 -2
- data/spec/models/posting_spec.rb +0 -13
- data/spec/services/jobs/schedule_spec.rb +40 -0
- data/spec/support/chromedriver.rb +2 -0
- metadata +27 -22
- data/spec/dummy/app/jobs/test_job2.rb +0 -4
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -34,8 +34,7 @@ module Marty::Diagnostic; class Nodes < Base
|
|
34
34
|
'shutting_down' => error_if(instances.shutting_down),
|
35
35
|
'terminated' => error_if(instances.terminated),
|
36
36
|
'stopping' => error_if(instances.stopping),
|
37
|
-
'stopped' => error_if(instances.stopped),
|
38
|
-
}.delete_if { |_k, v| v.empty? }
|
37
|
+
'stopped' => error_if(instances.stopped), }.delete_if { |_k, v| v.empty? }
|
39
38
|
rescue StandardError => e
|
40
39
|
error(e.message)
|
41
40
|
end
|
File without changes
|
@@ -9,7 +9,7 @@ module Marty::Diagnostic; class Reporter < Request
|
|
9
9
|
self.request = request
|
10
10
|
|
11
11
|
ops = op.split(/,\s*/).uniq - [unresolve_diagnostic(self)]
|
12
|
-
reps = ops.select { |o| reports.
|
12
|
+
reps = ops.select { |o| reports.key?(o) }
|
13
13
|
|
14
14
|
self.diagnostics = ((ops - reps) + reps.map { |r| reports[r] }.flatten).uniq.
|
15
15
|
map { |d| resolve_diagnostic(d) }
|
@@ -26,7 +26,7 @@ module Marty::Diagnostic; class Reporter < Request
|
|
26
26
|
klass = (n + '::Diagnostic::' + diag_name).constantize rescue nil
|
27
27
|
break if klass
|
28
28
|
end
|
29
|
-
raise NameError
|
29
|
+
raise NameError, "#{diag_name} could not be resolved by #{name}" if
|
30
30
|
klass.nil?
|
31
31
|
|
32
32
|
klass
|
File without changes
|
File without changes
|
File without changes
|
data/lib/marty/engine.rb
CHANGED
data/lib/marty/version.rb
CHANGED
data/lib/marty/xl.rb
CHANGED
@@ -190,7 +190,7 @@ class Marty::Xl
|
|
190
190
|
|
191
191
|
# counter == col0 == (colw - 1) => merge the edges:
|
192
192
|
a = boxborders[edge_h[r.object_id][1].to_sym] =
|
193
|
-
|
193
|
+
merge_cell_edges(a, deep_copy(boxborders[edge_h[r.object_id][1].to_sym])) if
|
194
194
|
counter == (colw - 1)
|
195
195
|
|
196
196
|
a = boxborders[edge_h[r.object_id][2].to_sym] unless
|
@@ -368,11 +368,11 @@ class Marty::Xl
|
|
368
368
|
[d[0], d[1], d[2].select { |inner| inner if inner[0] != 'pos' }]
|
369
369
|
end
|
370
370
|
new_ops = new_ops1 + new_ops2
|
371
|
-
count = new_ops.
|
372
|
-
d[2].
|
371
|
+
count = new_ops.count do |d|
|
372
|
+
d[2].count do |inner_ops|
|
373
373
|
inner_ops if inner_ops[0] == 'pos'
|
374
|
-
end
|
375
|
-
end
|
374
|
+
end > 0
|
375
|
+
end
|
376
376
|
|
377
377
|
count == 0 ? new_ops.sort : recalc_offsets(new_ops)
|
378
378
|
end
|
File without changes
|
@@ -46,10 +46,7 @@ module Dummy
|
|
46
46
|
config.active_support.escape_html_entities_in_json = true
|
47
47
|
|
48
48
|
# eager load paths instead of autoload paths
|
49
|
-
config.eager_load_paths
|
50
|
-
|dir|
|
51
|
-
File.expand_path("../../#{dir}", __FILE__)
|
52
|
-
end
|
49
|
+
config.eager_load_paths << File.expand_path("../../lib", __FILE__)
|
53
50
|
|
54
51
|
# Use SQL instead of Active Record's schema dumper when creating the database.
|
55
52
|
# This is necessary if your schema can't be completely dumped by the schema dumper,
|
@@ -1 +1 @@
|
|
1
|
-
Rails.application.config.assets.precompile
|
1
|
+
Rails.application.config.assets.precompile += ['*.js', '*.css']
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
feature 'on grid cells', js: true do
|
4
|
+
def go_to_user_view
|
5
|
+
press('System')
|
6
|
+
press('User Management')
|
7
|
+
wait_for_ajax
|
8
|
+
end
|
9
|
+
|
10
|
+
def go_to_data_grid_view
|
11
|
+
find(:xpath, "//a[contains(., 'Applications')]").click
|
12
|
+
press('Data Grids')
|
13
|
+
wait_for_ajax
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:uv) { netzke_find('user_view') }
|
17
|
+
|
18
|
+
before do
|
19
|
+
Mcfly.whodunnit = Marty::User.find_by_login('marty')
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'grid cells should encode html' do
|
23
|
+
log_in_as('marty')
|
24
|
+
go_to_user_view
|
25
|
+
|
26
|
+
by 'add user with html in field' do
|
27
|
+
wait_for_ajax
|
28
|
+
press('New User')
|
29
|
+
|
30
|
+
within(:gridpanel, 'add_window', match: :first) do
|
31
|
+
fill_in('Login', with: 'extjs_test_login')
|
32
|
+
fill_in('First Name', with: 'test_fname')
|
33
|
+
fill_in('Last Name',
|
34
|
+
with:
|
35
|
+
"<b class='test class' onclick='alert()'>test text</b>"
|
36
|
+
)
|
37
|
+
press 'Ok'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
and_by 'check html rendering' do
|
42
|
+
# negative test
|
43
|
+
expect do
|
44
|
+
find(:xpath, "//b[contains(@class, 'test class')]")
|
45
|
+
end.to raise_error(Capybara::ElementNotFound)
|
46
|
+
|
47
|
+
# positive test
|
48
|
+
find('tr', text: 'extjs_test_login').should have_content(
|
49
|
+
"<b class='test class' onclick='alert()'>test text</b>"
|
50
|
+
)
|
51
|
+
|
52
|
+
# positive test
|
53
|
+
find(:xpath, "//td[contains(., 'test text')]").click
|
54
|
+
go_to_data_grid_view
|
55
|
+
expect(URI.parse(current_url).fragment).to eq 'data_grid_user_view'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -26,7 +26,7 @@ feature 'Schedule Jobs Dashboard', js: true do
|
|
26
26
|
|
27
27
|
let!(:schedule) do
|
28
28
|
Marty::BackgroundJob::Schedule.create(
|
29
|
-
job_class: '
|
29
|
+
job_class: 'Test2Job',
|
30
30
|
cron: '0 0 * * *',
|
31
31
|
state: 'on'
|
32
32
|
).tap do |job|
|
@@ -38,7 +38,7 @@ feature 'Schedule Jobs Dashboard', js: true do
|
|
38
38
|
end
|
39
39
|
|
40
40
|
before do
|
41
|
-
expect(
|
41
|
+
expect(Test2Job.scheduled?).to be true
|
42
42
|
|
43
43
|
log_in_as('admin1')
|
44
44
|
wait_for_ajax
|
@@ -72,34 +72,34 @@ feature 'Schedule Jobs Dashboard', js: true do
|
|
72
72
|
expect(TestJob.scheduled?).to be true
|
73
73
|
expect(TestJob.delayed_job.cron).to eq '1 1 * * *'
|
74
74
|
|
75
|
-
expect(
|
76
|
-
expect(
|
75
|
+
expect(Test2Job.scheduled?).to be true
|
76
|
+
expect(Test2Job.delayed_job.cron).to eq '0 0 * * *'
|
77
77
|
end
|
78
78
|
|
79
79
|
it 'deletes schedule' do
|
80
|
-
find('.x-grid-item', text: '
|
80
|
+
find('.x-grid-item', text: 'Test2Job').click
|
81
81
|
press 'Delete'
|
82
82
|
press 'Yes'
|
83
83
|
|
84
84
|
wait_for_ajax
|
85
85
|
|
86
|
-
expect(
|
86
|
+
expect(Test2Job.scheduled?).to be false
|
87
87
|
end
|
88
88
|
|
89
89
|
it 'turns the schedule off' do
|
90
|
-
find('.x-grid-item', text: '
|
90
|
+
find('.x-grid-item', text: 'Test2Job').click
|
91
91
|
press 'Edit'
|
92
92
|
fill_in('state', with: 'off')
|
93
93
|
|
94
94
|
press 'OK'
|
95
95
|
wait_for_ajax
|
96
|
-
expect(
|
96
|
+
expect(Test2Job.scheduled?).to be false
|
97
97
|
end
|
98
98
|
|
99
99
|
it 'shows validation errors' do
|
100
100
|
press('Add')
|
101
101
|
|
102
|
-
fill_in('Job class', with: '
|
102
|
+
fill_in('Job class', with: 'Test2Job')
|
103
103
|
fill_in('state', with: 'on')
|
104
104
|
fill_in('cron', with: '1')
|
105
105
|
|
data/spec/lib/logger_spec.rb
CHANGED
@@ -101,9 +101,9 @@ module Marty
|
|
101
101
|
line_count = File.readlines('/tmp/logaction.txt').count
|
102
102
|
|
103
103
|
log_count = Marty::Log.all.count
|
104
|
-
failed_count = f.readlines.
|
104
|
+
failed_count = f.readlines.count do |l|
|
105
105
|
l == "Marty::Logger failure: database is locked\n"
|
106
|
-
end
|
106
|
+
end
|
107
107
|
|
108
108
|
expect(Marty::Promise.where.not(result: {}).count).to eq 1000
|
109
109
|
|
data/spec/models/posting_spec.rb
CHANGED
@@ -27,19 +27,6 @@ module Marty
|
|
27
27
|
expect(Posting.lookup_dt('NOW')).to eq Float::INFINITY
|
28
28
|
end
|
29
29
|
|
30
|
-
describe '.get_latest' do
|
31
|
-
it 'provide a list of latest of postings in descending order' do
|
32
|
-
4.times do |d|
|
33
|
-
Posting.do_create('BASE', d.day.from_now, 'a comment')
|
34
|
-
end
|
35
|
-
dt3 = 3.day.from_now
|
36
|
-
|
37
|
-
latest = Posting.get_latest(1)
|
38
|
-
expect(latest.count).to eq 1
|
39
|
-
expect(latest[0].name).to match /BASE-#{dt3.strftime("%Y%m%d-%H%M")}/
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
30
|
describe '.get_latest_by_type' do
|
44
31
|
context 'when invalid parameters are supplied' do
|
45
32
|
it "raises 'posting type list missing' error" do
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Marty
|
4
|
+
describe Jobs::Schedule do
|
5
|
+
let!(:schedule) do
|
6
|
+
Marty::BackgroundJob::Schedule.create!(
|
7
|
+
job_class: 'TestJob',
|
8
|
+
cron: '0 0 * * *',
|
9
|
+
state: 'on'
|
10
|
+
)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'schedules jobs' do
|
14
|
+
expect(TestJob).to_not be_scheduled
|
15
|
+
described_class.call
|
16
|
+
expect(TestJob).to be_scheduled
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'deletes previously scheduled jobs' do
|
20
|
+
described_class.call
|
21
|
+
expect(TestJob).to be_scheduled
|
22
|
+
schedule.destroy!
|
23
|
+
|
24
|
+
non_cron_job = Delayed::Job.create!(handler: 'Non cron job')
|
25
|
+
|
26
|
+
dj = Delayed::Job.last
|
27
|
+
dj.handler = dj.handler.gsub('TestJob', 'WrongTestJob')
|
28
|
+
dj.save!
|
29
|
+
|
30
|
+
described_class.call
|
31
|
+
|
32
|
+
expect(TestJob).to_not be_scheduled
|
33
|
+
any_old_scheduled_jobs = Delayed::Job.where('handler ILIKE ?', '%WrongTestJob%').any?
|
34
|
+
expect(any_old_scheduled_jobs).to be false
|
35
|
+
|
36
|
+
non_cron_job = Delayed::Job.find_by(handler: 'Non cron job')
|
37
|
+
expect(non_cron_job).to be_present
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -13,6 +13,8 @@ module Marty; module RSpec; module Chromedriver
|
|
13
13
|
}
|
14
14
|
|
15
15
|
options = ::Selenium::WebDriver::Chrome::Options.new
|
16
|
+
options.add_preference(:download, default_directory:
|
17
|
+
Marty::RSpec::DownloadHelper::PATH.to_s)
|
16
18
|
|
17
19
|
# Add arguments to the driver using the Options interface
|
18
20
|
if opts[:args]
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: marty
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 6.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Arman Bostani
|
@@ -14,7 +14,7 @@ authors:
|
|
14
14
|
autorequire:
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
|
-
date: 2019-
|
17
|
+
date: 2019-10-14 00:00:00.000000000 Z
|
18
18
|
dependencies:
|
19
19
|
- !ruby/object:Gem::Dependency
|
20
20
|
name: aws-sigv4
|
@@ -318,6 +318,7 @@ files:
|
|
318
318
|
- app/helpers/marty/enum_helper.rb
|
319
319
|
- app/helpers/marty/script_set.rb
|
320
320
|
- app/jobs/marty/cron_job.rb
|
321
|
+
- app/jobs/marty/remove_old_promises_job.rb
|
321
322
|
- app/models/marty/api_auth.rb
|
322
323
|
- app/models/marty/api_config.rb
|
323
324
|
- app/models/marty/background_job.rb
|
@@ -415,6 +416,7 @@ files:
|
|
415
416
|
- db/migrate/507_migrate_marty_roles_to_enum.rb
|
416
417
|
- db/migrate/508_add_not_to_data_grids_tables.rb
|
417
418
|
- db/migrate/509_update_dg_plpgsql_v1_fns.rb
|
419
|
+
- db/migrate/510_schedule_job_to_remove_old_promises.rb
|
418
420
|
- db/migrate/511_create_marty_delayed_job_logs.rb
|
419
421
|
- db/seeds.rb
|
420
422
|
- db/sql/lookup_grid_distinct_v1.sql
|
@@ -428,6 +430,7 @@ files:
|
|
428
430
|
- docker-compose.dummy.yml
|
429
431
|
- gemini_deprecations.md
|
430
432
|
- lib/marty.rb
|
433
|
+
- lib/marty/api/base.rb
|
431
434
|
- lib/marty/aws/base.rb
|
432
435
|
- lib/marty/aws/request.rb
|
433
436
|
- lib/marty/cache_adapters.rb
|
@@ -437,6 +440,23 @@ files:
|
|
437
440
|
- lib/marty/data_conversion.rb
|
438
441
|
- lib/marty/data_exporter.rb
|
439
442
|
- lib/marty/data_importer.rb
|
443
|
+
- lib/marty/diagnostic/aws/ec2_instance.rb
|
444
|
+
- lib/marty/diagnostic/aws/error.rb
|
445
|
+
- lib/marty/diagnostic/base.rb
|
446
|
+
- lib/marty/diagnostic/collection.rb
|
447
|
+
- lib/marty/diagnostic/connections.rb
|
448
|
+
- lib/marty/diagnostic/database.rb
|
449
|
+
- lib/marty/diagnostic/delayed_job_version.rb
|
450
|
+
- lib/marty/diagnostic/delayed_job_workers.rb
|
451
|
+
- lib/marty/diagnostic/environment_variables.rb
|
452
|
+
- lib/marty/diagnostic/fatal.rb
|
453
|
+
- lib/marty/diagnostic/node.rb
|
454
|
+
- lib/marty/diagnostic/nodes.rb
|
455
|
+
- lib/marty/diagnostic/packer.rb
|
456
|
+
- lib/marty/diagnostic/reporter.rb
|
457
|
+
- lib/marty/diagnostic/request.rb
|
458
|
+
- lib/marty/diagnostic/scheduled_jobs.rb
|
459
|
+
- lib/marty/diagnostic/version.rb
|
440
460
|
- lib/marty/engine.rb
|
441
461
|
- lib/marty/json_schema.rb
|
442
462
|
- lib/marty/logger.rb
|
@@ -464,24 +484,6 @@ files:
|
|
464
484
|
- lib/tasks/scripts_tasks.rake
|
465
485
|
- make-app.mk
|
466
486
|
- marty.gemspec
|
467
|
-
- other/marty/api/base.rb
|
468
|
-
- other/marty/diagnostic/aws/ec2_instance.rb
|
469
|
-
- other/marty/diagnostic/aws/error.rb
|
470
|
-
- other/marty/diagnostic/base.rb
|
471
|
-
- other/marty/diagnostic/collection.rb
|
472
|
-
- other/marty/diagnostic/connections.rb
|
473
|
-
- other/marty/diagnostic/database.rb
|
474
|
-
- other/marty/diagnostic/delayed_job_version.rb
|
475
|
-
- other/marty/diagnostic/delayed_job_workers.rb
|
476
|
-
- other/marty/diagnostic/environment_variables.rb
|
477
|
-
- other/marty/diagnostic/fatal.rb
|
478
|
-
- other/marty/diagnostic/node.rb
|
479
|
-
- other/marty/diagnostic/nodes.rb
|
480
|
-
- other/marty/diagnostic/packer.rb
|
481
|
-
- other/marty/diagnostic/reporter.rb
|
482
|
-
- other/marty/diagnostic/request.rb
|
483
|
-
- other/marty/diagnostic/scheduled_jobs.rb
|
484
|
-
- other/marty/diagnostic/version.rb
|
485
487
|
- script/rails
|
486
488
|
- spec/controllers/application_controller_spec.rb
|
487
489
|
- spec/controllers/delayed_job_controller_spec.rb
|
@@ -491,6 +493,7 @@ files:
|
|
491
493
|
- spec/controllers/rpc_import_spec.rb
|
492
494
|
- spec/dummy/README.rdoc
|
493
495
|
- spec/dummy/Rakefile
|
496
|
+
- spec/dummy/app/assets/config/manifest.js
|
494
497
|
- spec/dummy/app/components/gemini/cm_auth_app.rb
|
495
498
|
- spec/dummy/app/components/gemini/loan_program_view.rb
|
496
499
|
- spec/dummy/app/components/gemini/my_rule_view.rb
|
@@ -498,8 +501,8 @@ files:
|
|
498
501
|
- spec/dummy/app/controllers/application_controller.rb
|
499
502
|
- spec/dummy/app/controllers/components_controller.rb
|
500
503
|
- spec/dummy/app/helpers/application_helper.rb
|
504
|
+
- spec/dummy/app/jobs/test2_job.rb
|
501
505
|
- spec/dummy/app/jobs/test_job.rb
|
502
|
-
- spec/dummy/app/jobs/test_job2.rb
|
503
506
|
- spec/dummy/app/mailers/.gitkeep
|
504
507
|
- spec/dummy/app/models/.gitkeep
|
505
508
|
- spec/dummy/app/models/gemini/amortization_type.rb
|
@@ -1598,6 +1601,7 @@ files:
|
|
1598
1601
|
- spec/features/data_import_spec.rb
|
1599
1602
|
- spec/features/endpoint_access.rb
|
1600
1603
|
- spec/features/enum_spec.rb
|
1604
|
+
- spec/features/extjs_spec.rb
|
1601
1605
|
- spec/features/javascripts/job_dashboard_live_search.js.coffee
|
1602
1606
|
- spec/features/javascripts/login.js.coffee
|
1603
1607
|
- spec/features/jobs_dashboard_spec.rb
|
@@ -1662,6 +1666,7 @@ files:
|
|
1662
1666
|
- spec/other/diagnostic/delayed_job_workers_spec.rb
|
1663
1667
|
- spec/other/diagnostic/reporter_spec.rb
|
1664
1668
|
- spec/requests/routes_spec.rb
|
1669
|
+
- spec/services/jobs/schedule_spec.rb
|
1665
1670
|
- spec/spec_helper.rb
|
1666
1671
|
- spec/support/chromedriver.rb
|
1667
1672
|
- spec/support/components/netzke_combobox.rb
|
@@ -1700,7 +1705,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
1700
1705
|
- !ruby/object:Gem::Version
|
1701
1706
|
version: '0'
|
1702
1707
|
requirements: []
|
1703
|
-
rubygems_version: 3.0.
|
1708
|
+
rubygems_version: 3.0.6
|
1704
1709
|
signing_key:
|
1705
1710
|
specification_version: 4
|
1706
1711
|
summary: A framework for working with versioned data
|