ietf-data-importer 0.3.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 +7 -0
- data/.github/workflows/check_update.yml +44 -0
- data/.github/workflows/rake.yml +15 -0
- data/.github/workflows/release.yml +25 -0
- data/.gitignore +2 -0
- data/.rubocop.yml +10 -0
- data/Gemfile +11 -0
- data/README.adoc +220 -0
- data/Rakefile +8 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/exe/ietf-data-importer +6 -0
- data/ietf-data-importer.gemspec +37 -0
- data/lib/ietf/data/importer/cli.rb +47 -0
- data/lib/ietf/data/importer/group.rb +42 -0
- data/lib/ietf/data/importer/group_collection.rb +19 -0
- data/lib/ietf/data/importer/groups.yaml +1745 -0
- data/lib/ietf/data/importer/scrapers/base_scraper.rb +33 -0
- data/lib/ietf/data/importer/scrapers/ietf_scraper.rb +272 -0
- data/lib/ietf/data/importer/scrapers/irtf_scraper.rb +350 -0
- data/lib/ietf/data/importer/scrapers.rb +64 -0
- data/lib/ietf/data/importer/version.rb +9 -0
- data/lib/ietf/data/importer.rb +93 -0
- metadata +126 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 0df7ab18290351d1560ddc5e0f0e1e5d976028045f22b6f4b87b89f25f747ffc
|
4
|
+
data.tar.gz: c814b6d33bced977dd20c9c0c3f0f8553007a095eb53116f6c740238eb29a870
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9b9d8d45a4d9997c0e8f3118c61140f8986bdb169d2379d42f7aee0ee8ef25f6b957db4f66531825a2aac415f940eb1f66b4f4d85c1d89b70fc66045b91e1018
|
7
|
+
data.tar.gz: aa884d901083552f00b086908bbfcc269a5b71d971d493d4333291b9ba02c774441dfb1e6c9b54eff4689ac0656624969e7fdb98f5b1716e5c8275635cea2342
|
@@ -0,0 +1,44 @@
|
|
1
|
+
name: check_update
|
2
|
+
|
3
|
+
on:
|
4
|
+
schedule:
|
5
|
+
- cron: "0 0 * * *"
|
6
|
+
workflow_dispatch:
|
7
|
+
|
8
|
+
jobs:
|
9
|
+
check_update:
|
10
|
+
name: Check workgroups update
|
11
|
+
runs-on: ubuntu-latest
|
12
|
+
steps:
|
13
|
+
- uses: actions/checkout@v2
|
14
|
+
|
15
|
+
- run: |
|
16
|
+
git config user.name github-actions
|
17
|
+
git config user.email github-actions@github.com
|
18
|
+
|
19
|
+
- uses: ruby/setup-ruby@v1
|
20
|
+
with:
|
21
|
+
ruby-version: '2.6'
|
22
|
+
bundler-cache: true
|
23
|
+
|
24
|
+
- id: update_json
|
25
|
+
run: |
|
26
|
+
bundle exec bin/wg2json.rb > lib/metanorma/ietf/data/workgroups.json
|
27
|
+
git diff-index --quiet HEAD -- && has_changes="false" || has_changes="true"
|
28
|
+
echo "::set-output name=has_changes::${has_changes}"
|
29
|
+
|
30
|
+
- if: ${{ !steps.update_json.outputs.has_changes == 'true' }}
|
31
|
+
run: gem bump --version patch --tag --push
|
32
|
+
|
33
|
+
- if: ${{ !steps.update_json.outputs.has_changes == 'true' }}
|
34
|
+
name: publish to rubygems.org
|
35
|
+
env:
|
36
|
+
RUBYGEMS_API_KEY: ${{secrets.METANORMA_CI_RUBYGEMS_API_KEY}}
|
37
|
+
run: |
|
38
|
+
gem install gem-release
|
39
|
+
envsubst << 'EOF' > ~/.gem/credentials
|
40
|
+
---
|
41
|
+
:rubygems_api_key: ${RUBYGEMS_API_KEY}
|
42
|
+
EOF
|
43
|
+
chmod 0600 ~/.gem/credentials
|
44
|
+
gem release
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# Auto-generated by Cimas: Do not edit it manually!
|
2
|
+
# See https://github.com/metanorma/cimas
|
3
|
+
name: rake
|
4
|
+
|
5
|
+
on:
|
6
|
+
push:
|
7
|
+
branches: [ master, main ]
|
8
|
+
tags: [ v* ]
|
9
|
+
pull_request:
|
10
|
+
|
11
|
+
jobs:
|
12
|
+
rake:
|
13
|
+
uses: metanorma/ci/.github/workflows/generic-rake.yml@main
|
14
|
+
secrets:
|
15
|
+
pat_token: ${{ secrets.METANORMA_CI_PAT_TOKEN }}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# Auto-generated by Cimas: Do not edit it manually!
|
2
|
+
# See https://github.com/metanorma/cimas
|
3
|
+
name: release
|
4
|
+
|
5
|
+
on:
|
6
|
+
workflow_dispatch:
|
7
|
+
inputs:
|
8
|
+
next_version:
|
9
|
+
description: |
|
10
|
+
Next release version. Possible values: x.y.z, major, minor, patch (or pre|rc|etc).
|
11
|
+
Also, you can pass 'skip' to skip 'git tag' and do 'gem push' for the current version
|
12
|
+
required: true
|
13
|
+
default: 'skip'
|
14
|
+
repository_dispatch:
|
15
|
+
types: [ do-release ]
|
16
|
+
|
17
|
+
jobs:
|
18
|
+
release:
|
19
|
+
uses: metanorma/ci/.github/workflows/rubygems-release.yml@main
|
20
|
+
with:
|
21
|
+
next_version: ${{ github.event.inputs.next_version }}
|
22
|
+
secrets:
|
23
|
+
rubygems-api-key: ${{ secrets.METANORMA_CI_RUBYGEMS_API_KEY }}
|
24
|
+
pat_token: ${{ secrets.METANORMA_CI_PAT_TOKEN }}
|
25
|
+
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
# Auto-generated by Cimas: Do not edit it manually!
|
2
|
+
# See https://github.com/metanorma/cimas
|
3
|
+
inherit_from:
|
4
|
+
- https://raw.githubusercontent.com/riboseinc/oss-guides/master/ci/rubocop.yml
|
5
|
+
|
6
|
+
# local repo-specific modifications
|
7
|
+
# ...
|
8
|
+
|
9
|
+
AllCops:
|
10
|
+
TargetRubyVersion: 2.5
|
data/Gemfile
ADDED
data/README.adoc
ADDED
@@ -0,0 +1,220 @@
|
|
1
|
+
= IETF Data Importer
|
2
|
+
|
3
|
+
image:https://img.shields.io/gem/v/ietf-data-importer.svg["Gem Version", link="https://rubygems.org/gems/ietf-data-importer"]
|
4
|
+
image:https://github.com/metanorma/ietf-data-importer/actions/workflows/rake.yml/badge.svg["Build Status", link="https://github.com/metanorma/ietf-data-importer/actions/workflows/rake.yml"]
|
5
|
+
image:https://img.shields.io/github/issues-pr-raw/metanorma/ietf-data-importer.svg["Pull Requests", link="https://github.com/metanorma/ietf-data-importer/pulls"]
|
6
|
+
image:https://img.shields.io/github/commits-since/metanorma/ietf-data-importer/latest.svg["Commits since latest", link="https://github.com/metanorma/ietf-data-importer/releases"]
|
7
|
+
|
8
|
+
== Purpose
|
9
|
+
|
10
|
+
IETF Data Importer is a Ruby gem providing access to information about IETF working groups and IRTF research groups.
|
11
|
+
|
12
|
+
It includes:
|
13
|
+
|
14
|
+
* Data models for IETF and IRTF groups
|
15
|
+
* Command-line tools for fetching and updating group data
|
16
|
+
* A Ruby API for accessing group information
|
17
|
+
|
18
|
+
This gem exists because the official sources often change their layout or may be unavailable:
|
19
|
+
|
20
|
+
* https://datatracker.ietf.org/group/ (formerly tools.ietf.org/wg)
|
21
|
+
* https://irtf.org/groups
|
22
|
+
|
23
|
+
== Migration from metanorma-ietf-data
|
24
|
+
|
25
|
+
This gem is the renamed and restructured version of `metanorma-ietf-data`. The namespace and file structure have been changed to match other Metanorma data importer gems.
|
26
|
+
|
27
|
+
To migrate from metanorma-ietf-data:
|
28
|
+
|
29
|
+
. Replace the following:
|
30
|
+
+
|
31
|
+
[source,diff]
|
32
|
+
----
|
33
|
+
- require "metanorma/ietf/data"
|
34
|
+
- groups = Metanorma::Ietf::Data.groups
|
35
|
+
+ require "ietf/data/importer"
|
36
|
+
+ groups = Ietf::Data::Importer.groups
|
37
|
+
----
|
38
|
+
|
39
|
+
. Update your Gemfile:
|
40
|
+
+
|
41
|
+
[source,diff]
|
42
|
+
----
|
43
|
+
- gem 'metanorma-ietf-data'
|
44
|
+
+ gem 'ietf-data-importer'
|
45
|
+
----
|
46
|
+
|
47
|
+
== Installation
|
48
|
+
|
49
|
+
Add this line to your application's Gemfile:
|
50
|
+
|
51
|
+
[source,ruby]
|
52
|
+
----
|
53
|
+
gem 'ietf-data-importer'
|
54
|
+
----
|
55
|
+
|
56
|
+
And then execute:
|
57
|
+
|
58
|
+
[source,shell]
|
59
|
+
----
|
60
|
+
$ bundle install
|
61
|
+
----
|
62
|
+
|
63
|
+
Or install it yourself as:
|
64
|
+
|
65
|
+
[source,shell]
|
66
|
+
----
|
67
|
+
$ gem install ietf-data-importer
|
68
|
+
----
|
69
|
+
|
70
|
+
== Usage
|
71
|
+
|
72
|
+
=== For YAML/JSON data users
|
73
|
+
|
74
|
+
The gem provides a command-line tool to fetch current group data:
|
75
|
+
|
76
|
+
[source,shell]
|
77
|
+
----
|
78
|
+
$ ietf-data-importer fetch output.yaml
|
79
|
+
$ ietf-data-importer fetch output.json --format=json
|
80
|
+
----
|
81
|
+
|
82
|
+
=== For Ruby API users
|
83
|
+
|
84
|
+
[source,ruby]
|
85
|
+
----
|
86
|
+
require 'ietf/data/importer'
|
87
|
+
|
88
|
+
# Check if a group exists
|
89
|
+
Ietf::Data::Importer.group_exists?('httpbis')
|
90
|
+
|
91
|
+
# Get information about a specific group
|
92
|
+
group = Ietf::Data::Importer.find_group('httpbis')
|
93
|
+
puts group.name
|
94
|
+
puts group.organization
|
95
|
+
puts group.status
|
96
|
+
|
97
|
+
# Get all IETF working groups
|
98
|
+
wgs = Ietf::Data::Importer.working_groups
|
99
|
+
|
100
|
+
# Get all IRTF research groups
|
101
|
+
rgs = Ietf::Data::Importer.research_groups
|
102
|
+
|
103
|
+
# Get groups by a specific type
|
104
|
+
type_groups = Ietf::Data::Importer.groups_by_type('wg')
|
105
|
+
|
106
|
+
# Get groups by area
|
107
|
+
area_groups = Ietf::Data::Importer.groups_by_area('Applications and Real-Time Area')
|
108
|
+
|
109
|
+
# Get active or concluded groups
|
110
|
+
active = Ietf::Data::Importer.active_groups
|
111
|
+
concluded = Ietf::Data::Importer.concluded_groups
|
112
|
+
|
113
|
+
# Get all available group types
|
114
|
+
types = Ietf::Data::Importer.group_types
|
115
|
+
|
116
|
+
# Get all areas
|
117
|
+
areas = Ietf::Data::Importer.areas
|
118
|
+
----
|
119
|
+
|
120
|
+
== Data model
|
121
|
+
|
122
|
+
=== Organizations
|
123
|
+
|
124
|
+
[options="header"]
|
125
|
+
|===
|
126
|
+
| Organization | Abbreviation | Description
|
127
|
+
| Internet Engineering Task Force | ietf | Standards development organization
|
128
|
+
| Internet Research Task Force | irtf | Research organization
|
129
|
+
|===
|
130
|
+
|
131
|
+
=== Group types
|
132
|
+
|
133
|
+
[options="header"]
|
134
|
+
|===
|
135
|
+
| Type | Abbreviation | Organization | Description
|
136
|
+
| Working Group | wg | ietf | IETF working groups
|
137
|
+
| Research Group | rg | irtf | IRTF research groups
|
138
|
+
| Area | area | ietf | IETF areas
|
139
|
+
| Team | team | ietf | IETF administrative teams
|
140
|
+
| Program | program | irtf | IRTF programs
|
141
|
+
| Directorate | dir | ietf | IETF directorates
|
142
|
+
| Advisory Group | ag | ietf/irtf | Advisory groups
|
143
|
+
|===
|
144
|
+
|
145
|
+
=== Status values
|
146
|
+
|
147
|
+
[options="header"]
|
148
|
+
|===
|
149
|
+
| Status | Description
|
150
|
+
| active | Group is currently active
|
151
|
+
| concluded | Group has completed its work
|
152
|
+
| bof | Birds of a Feather (BOF) session
|
153
|
+
| proposed | Proposed but not yet approved
|
154
|
+
|===
|
155
|
+
|
156
|
+
== Command-line interface
|
157
|
+
|
158
|
+
The gem provides a command-line tool with the following commands:
|
159
|
+
|
160
|
+
[source,shell]
|
161
|
+
----
|
162
|
+
# Fetch current IETF/IRTF group data
|
163
|
+
$ ietf-data-importer fetch [OUTPUT_FILE] --format=yaml|json
|
164
|
+
|
165
|
+
# Integrate a YAML file into the gem for distribution
|
166
|
+
$ ietf-data-importer integrate YAML_FILE
|
167
|
+
----
|
168
|
+
|
169
|
+
== Data schema
|
170
|
+
|
171
|
+
The YAML/JSON data follows this schema:
|
172
|
+
|
173
|
+
[source,yaml]
|
174
|
+
----
|
175
|
+
groups:
|
176
|
+
- abbreviation: string # Group abbreviation or acronym
|
177
|
+
name: string # Full group name
|
178
|
+
organization: string # 'ietf' or 'irtf'
|
179
|
+
type: string # Group type (see table above)
|
180
|
+
area: string # Area name (for IETF WGs)
|
181
|
+
status: string # Group status
|
182
|
+
description: string # Description or charter text
|
183
|
+
chairs: # Array of chairs
|
184
|
+
- string # Chair name
|
185
|
+
mailing_list: string # Mailing list address
|
186
|
+
mailing_list_archive: string # Archive URL
|
187
|
+
website_url: string # Group website URL
|
188
|
+
charter_url: string # Charter document URL
|
189
|
+
concluded_date: string # ISO date of conclusion (if applicable)
|
190
|
+
----
|
191
|
+
|
192
|
+
[example]
|
193
|
+
====
|
194
|
+
[source,yaml]
|
195
|
+
----
|
196
|
+
groups:
|
197
|
+
- abbreviation: httpbis
|
198
|
+
name: HTTP
|
199
|
+
organization: ietf
|
200
|
+
type: wg
|
201
|
+
area: Applications and Real-Time Area
|
202
|
+
status: active
|
203
|
+
description: The HTTP working group is chartered to maintain and develop the Hypertext Transfer Protocol...
|
204
|
+
chairs:
|
205
|
+
- Chair Person 1
|
206
|
+
- Chair Person 2
|
207
|
+
mailing_list: httpbis@ietf.org
|
208
|
+
mailing_list_archive: https://mailarchive.ietf.org/arch/browse/httpbis/
|
209
|
+
website_url: https://httpwg.org/
|
210
|
+
charter_url: https://datatracker.ietf.org/wg/httpbis/about/
|
211
|
+
----
|
212
|
+
====
|
213
|
+
|
214
|
+
== Copyright
|
215
|
+
|
216
|
+
This gem is developed, maintained and funded by https://www.ribose.com[Ribose Inc.]
|
217
|
+
|
218
|
+
== License
|
219
|
+
|
220
|
+
The gem is available as open source under the terms of the https://opensource.org/licenses/BSD-2-Clause[2-Clause BSD License].
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "bundler/setup"
|
5
|
+
require "ietf/data/importer"
|
6
|
+
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
9
|
+
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
11
|
+
# require "pry"
|
12
|
+
# Pry.start
|
13
|
+
|
14
|
+
require "irb"
|
15
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/ietf/data/importer/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "ietf-data-importer"
|
7
|
+
spec.version = Ietf::Data::Importer::VERSION
|
8
|
+
spec.authors = ["Ribose Inc."]
|
9
|
+
spec.email = ["open.source@ribose.com"]
|
10
|
+
|
11
|
+
spec.summary = <<~SUMMARY
|
12
|
+
Offline access to IETF working groups and IRTF research groups metadata
|
13
|
+
SUMMARY
|
14
|
+
spec.description = <<~DESCRIPTION
|
15
|
+
ietf-data-importer offers reliable offline access to metadata for IETF working groups
|
16
|
+
and IRTF research groups. This provides a dependable alternative to the official
|
17
|
+
resources at https://tools.ietf.org/wg/ and https://irtf.org/groups, which may
|
18
|
+
experience downtime or connectivity issues.
|
19
|
+
DESCRIPTION
|
20
|
+
spec.homepage = "https://github.com/metanorma/ietf-data-importer"
|
21
|
+
spec.license = "BSD-2-Clause"
|
22
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 3.0.0")
|
23
|
+
|
24
|
+
spec.add_dependency "lutaml-model", "~> 0.7"
|
25
|
+
spec.add_dependency "thor", "~> 1.0"
|
26
|
+
spec.add_dependency "nokogiri", "~> 1.18"
|
27
|
+
spec.add_dependency "yaml"
|
28
|
+
|
29
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
30
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
31
|
+
f.match(%r{\A(?:test|spec|features)/})
|
32
|
+
end
|
33
|
+
end
|
34
|
+
spec.bindir = "exe"
|
35
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
36
|
+
spec.require_paths = ["lib"]
|
37
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "thor"
|
4
|
+
require "yaml"
|
5
|
+
require "fileutils"
|
6
|
+
require_relative "group_collection"
|
7
|
+
require_relative "scrapers"
|
8
|
+
|
9
|
+
module Ietf
|
10
|
+
module Data
|
11
|
+
module Importer
|
12
|
+
# Command-line interface for IETF/IRTF group data
|
13
|
+
class Cli < Thor
|
14
|
+
desc "fetch OUTPUT_FILE", "Fetch IETF/IRTF groups and save to YAML file"
|
15
|
+
option :format, type: :string, default: "yaml", desc: "Output format (yaml or json)"
|
16
|
+
def fetch(output_file = nil)
|
17
|
+
output_file ||= "ietf_groups.#{options[:format]}"
|
18
|
+
|
19
|
+
# Fetch all groups using the scrapers
|
20
|
+
collection = Ietf::Data::Importer::Scrapers.fetch_all
|
21
|
+
|
22
|
+
# Save to file in the requested format
|
23
|
+
format = options[:format].to_sym
|
24
|
+
Ietf::Data::Importer::Scrapers.save_to_file(collection, output_file, format)
|
25
|
+
end
|
26
|
+
|
27
|
+
desc "integrate YAML_FILE", "Integrate YAML file as gem data"
|
28
|
+
def integrate(yaml_file)
|
29
|
+
# Validate YAML file
|
30
|
+
begin
|
31
|
+
collection = Ietf::Data::Importer::GroupCollection.from_yaml(File.read(yaml_file))
|
32
|
+
rescue => e
|
33
|
+
puts "Error reading YAML file: #{e.message}"
|
34
|
+
exit 1
|
35
|
+
end
|
36
|
+
|
37
|
+
# Save as YAML for gem usage
|
38
|
+
target_yaml = File.join(File.dirname(__FILE__), "groups.yaml")
|
39
|
+
FileUtils.mkdir_p(File.dirname(target_yaml))
|
40
|
+
File.write(target_yaml, File.read(yaml_file))
|
41
|
+
|
42
|
+
puts "Integrated #{collection.groups.size} groups into gem"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "lutaml/model"
|
4
|
+
|
5
|
+
module Ietf
|
6
|
+
module Data
|
7
|
+
module Importer
|
8
|
+
# Represents a single IETF or IRTF group
|
9
|
+
class Group < Lutaml::Model::Serializable
|
10
|
+
attribute :abbreviation, :string
|
11
|
+
attribute :name, :string
|
12
|
+
attribute :organization, :string # 'ietf' or 'irtf'
|
13
|
+
attribute :type, :string # 'wg', 'rg', etc.
|
14
|
+
attribute :area, :string
|
15
|
+
attribute :status, :string, values: %w[active concluded bof proposed]
|
16
|
+
attribute :description, :string
|
17
|
+
attribute :chairs, :string, collection: true
|
18
|
+
attribute :mailing_list, :string
|
19
|
+
attribute :mailing_list_archive, :string
|
20
|
+
attribute :website_url, :string
|
21
|
+
attribute :charter_url, :string
|
22
|
+
attribute :concluded_date, :date
|
23
|
+
|
24
|
+
key_value do
|
25
|
+
map "abbreviation", to: :abbreviation
|
26
|
+
map "name", to: :name
|
27
|
+
map "organization", to: :organization
|
28
|
+
map "type", to: :type
|
29
|
+
map "area", to: :area
|
30
|
+
map "status", to: :status
|
31
|
+
map "description", to: :description
|
32
|
+
map "chairs", to: :chairs
|
33
|
+
map "mailing_list", to: :mailing_list
|
34
|
+
map "mailing_list_archive", to: :mailing_list_archive
|
35
|
+
map "website_url", to: :website_url
|
36
|
+
map "charter_url", to: :charter_url
|
37
|
+
map "concluded_date", to: :concluded_date
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "lutaml/model"
|
4
|
+
require_relative "group"
|
5
|
+
|
6
|
+
module Ietf
|
7
|
+
module Data
|
8
|
+
module Importer
|
9
|
+
# Represents a collection of IETF and IRTF groups
|
10
|
+
class GroupCollection < Lutaml::Model::Serializable
|
11
|
+
attribute :groups, Group, collection: true
|
12
|
+
|
13
|
+
key_value do
|
14
|
+
map "groups", to: :groups
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|