meibo 0.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.
Files changed (75) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +13 -0
  4. data/CHANGELOG.md +5 -0
  5. data/CODE_OF_CONDUCT.md +84 -0
  6. data/Gemfile +16 -0
  7. data/Gemfile.lock +84 -0
  8. data/LICENSE.txt +21 -0
  9. data/README.md +41 -0
  10. data/Rakefile +12 -0
  11. data/lib/meibo/academic_session.rb +48 -0
  12. data/lib/meibo/academic_session_set.rb +15 -0
  13. data/lib/meibo/base_profile.rb +37 -0
  14. data/lib/meibo/builder/academic_session_builder.rb +26 -0
  15. data/lib/meibo/builder/base_builder.rb +13 -0
  16. data/lib/meibo/builder/classroom_builder.rb +38 -0
  17. data/lib/meibo/builder/course_builder.rb +32 -0
  18. data/lib/meibo/builder/demographic_builder.rb +22 -0
  19. data/lib/meibo/builder/enrollment_builder.rb +30 -0
  20. data/lib/meibo/builder/organization_builder.rb +34 -0
  21. data/lib/meibo/builder/role_builder.rb +30 -0
  22. data/lib/meibo/builder/user_builder.rb +36 -0
  23. data/lib/meibo/builder/user_profile_builder.rb +22 -0
  24. data/lib/meibo/builder.rb +60 -0
  25. data/lib/meibo/classroom.rb +67 -0
  26. data/lib/meibo/classroom_set.rb +29 -0
  27. data/lib/meibo/converter.rb +259 -0
  28. data/lib/meibo/course.rb +45 -0
  29. data/lib/meibo/course_set.rb +23 -0
  30. data/lib/meibo/data_model.rb +84 -0
  31. data/lib/meibo/data_set.rb +44 -0
  32. data/lib/meibo/demographic.rb +70 -0
  33. data/lib/meibo/demographic_set.rb +18 -0
  34. data/lib/meibo/enrollment.rb +51 -0
  35. data/lib/meibo/enrollment_set.rb +22 -0
  36. data/lib/meibo/errors.rb +13 -0
  37. data/lib/meibo/factory_bot/academic_session.rb +23 -0
  38. data/lib/meibo/factory_bot/all.rb +13 -0
  39. data/lib/meibo/factory_bot/classroom.rb +28 -0
  40. data/lib/meibo/factory_bot/course.rb +21 -0
  41. data/lib/meibo/factory_bot/demographic.rb +16 -0
  42. data/lib/meibo/factory_bot/enrollment.rb +37 -0
  43. data/lib/meibo/factory_bot/manifest.rb +33 -0
  44. data/lib/meibo/factory_bot/memory_package.rb +11 -0
  45. data/lib/meibo/factory_bot/organization.rb +47 -0
  46. data/lib/meibo/factory_bot/role.rb +41 -0
  47. data/lib/meibo/factory_bot/user.rb +22 -0
  48. data/lib/meibo/factory_bot/user_profile.rb +21 -0
  49. data/lib/meibo/japan_profile/academic_session.rb +26 -0
  50. data/lib/meibo/japan_profile/classroom.rb +21 -0
  51. data/lib/meibo/japan_profile/course.rb +18 -0
  52. data/lib/meibo/japan_profile/demographic.rb +15 -0
  53. data/lib/meibo/japan_profile/enrollment.rb +35 -0
  54. data/lib/meibo/japan_profile/organization.rb +20 -0
  55. data/lib/meibo/japan_profile/role.rb +26 -0
  56. data/lib/meibo/japan_profile/user.rb +27 -0
  57. data/lib/meibo/japan_profile/user_profile.rb +7 -0
  58. data/lib/meibo/japan_profile.rb +39 -0
  59. data/lib/meibo/manifest/processing_mode.rb +40 -0
  60. data/lib/meibo/manifest.rb +163 -0
  61. data/lib/meibo/organization.rb +44 -0
  62. data/lib/meibo/organization_set.rb +15 -0
  63. data/lib/meibo/reader.rb +138 -0
  64. data/lib/meibo/role.rb +65 -0
  65. data/lib/meibo/role_set.rb +25 -0
  66. data/lib/meibo/roster.rb +166 -0
  67. data/lib/meibo/user.rb +71 -0
  68. data/lib/meibo/user_profile.rb +42 -0
  69. data/lib/meibo/user_profile_set.rb +18 -0
  70. data/lib/meibo/user_set.rb +24 -0
  71. data/lib/meibo/version.rb +5 -0
  72. data/lib/meibo.rb +17 -0
  73. data/meibo.gemspec +38 -0
  74. data/sig/meibo.rbs +4 -0
  75. metadata +148 -0
@@ -0,0 +1,166 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'zip'
4
+ require 'csv'
5
+
6
+ module Meibo
7
+ class Roster
8
+ class << self
9
+ def from_file(file_path, profile: BaseProfile)
10
+ Reader.open(file_path, profile: profile) do |reader|
11
+ begin
12
+ manifest = reader.manifest
13
+ rescue CsvFileNotFoundError
14
+ raise NotSupportedError, 'OneRoster 1.0はサポートしていません'
15
+ rescue
16
+ raise NotSupportedError, "#{Meibo::Manifest.filename}の読み込みに失敗しました"
17
+ end
18
+
19
+ validate_manifest_version(manifest.manifest_version)
20
+ validate_oneroster_version(manifest.oneroster_version)
21
+ validate_supported_processing_mode(manifest)
22
+ processing_modes = Meibo::Manifest::PROCESSING_MODES
23
+ validate_absent_files(reader, manifest.filenames(processing_mode: processing_modes[:absent]))
24
+ validate_bulk_files(reader, manifest.filenames(processing_mode: processing_modes[:bulk]))
25
+
26
+ new(manifest_properties: manifest.to_h, profile: profile, **reader.load_bulk_files).tap(&:check_semantically_consistent)
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def validate_absent_files(reader, absent_filenames)
33
+ absent_filenames.each do |absent_filename|
34
+ next unless reader.file_entry?(absent_filename)
35
+
36
+ raise NotSupportedError, "#{absent_filename}が存在します"
37
+ end
38
+ end
39
+
40
+ def validate_bulk_files(reader, bulk_filenames)
41
+ bulk_filenames.each do |bulk_filename|
42
+ next if reader.file_entry?(bulk_filename)
43
+
44
+ raise NotSupportedError, "#{bulk_filename}が存在しません"
45
+ end
46
+ end
47
+
48
+ def validate_manifest_version(manifest_version)
49
+ return if manifest_version == Meibo::Manifest::MANIFEST_VERSION
50
+
51
+ raise NotSupportedError, "manifest.version: #{manifest_version}はサポートしていません"
52
+ end
53
+
54
+ def validate_oneroster_version(oneroster_version)
55
+ return if oneroster_version == Meibo::Manifest::ONEROSTER_VERSION
56
+
57
+ raise NotSupportedError, "oneroster.version: #{oneroster_version}はサポートしていません"
58
+ end
59
+
60
+ def validate_supported_processing_mode(manifest)
61
+ return if manifest.file_attributes(processing_mode: Meibo::Manifest::PROCESSING_MODES[:delta]).empty?
62
+
63
+ raise NotSupportedError, 'DELTAはサポートしていません'
64
+ end
65
+ end
66
+
67
+ attr_reader :profile, :manifest_properties, :academic_sessions, :classes, :courses, :demographics, :enrollments, :organizations, :roles, :user_profiles, :users
68
+
69
+ def initialize(profile: BaseProfile, manifest_properties: {}, academic_sessions: [], classes: [], courses: [], demographics: [], enrollments: [], organizations: [], roles: [], user_profiles: [], users: [])
70
+ @profile = profile
71
+ @manifest_properties = manifest_properties
72
+ @academic_sessions = AcademicSessionSet.new(academic_sessions)
73
+ @organizations = OrganizationSet.new(organizations)
74
+ @courses = CourseSet.new(courses, academic_session_set: @academic_sessions, organization_set: @organizations)
75
+ @classes = ClassroomSet.new(classes, academic_session_set: @academic_sessions, course_set: @courses, organization_set: @organizations)
76
+ @users = UserSet.new(users, organization_set: @organizations)
77
+ @demographics = DemographicSet.new(demographics, user_set: @users)
78
+ @user_profiles = UserProfileSet.new(user_profiles, user_set: @users)
79
+ @roles = RoleSet.new(roles, organization_set: @organizations, user_set: @users, user_profile_set: @user_profiles)
80
+ @enrollments = EnrollmentSet.new(enrollments, classroom_set: @classes, organization_set: @organizations, user_set: @users)
81
+ end
82
+
83
+ def check_semantically_consistent
84
+ [
85
+ academic_sessions,
86
+ classes,
87
+ courses,
88
+ demographics,
89
+ enrollments,
90
+ organizations,
91
+ roles,
92
+ user_profiles,
93
+ users
94
+ ].each(&:check_semantically_consistent)
95
+ end
96
+
97
+ def write(path)
98
+ Zip::File.open(path, ::Zip::File::CREATE) do |zipfile|
99
+ manifest = build_manifest
100
+ zipfile.get_output_stream(::Meibo::Manifest.filename) do |f|
101
+ f.puts ::Meibo::Manifest.header_fields.to_csv
102
+ manifest.to_a.each do |row|
103
+ f.puts row.to_csv
104
+ end
105
+ end
106
+ file_properties.each do |file_attribute, processing_mode|
107
+ next if processing_mode.absent?
108
+
109
+ klass = profile.data_model_for(file_attribute)
110
+ filename = Manifest.filename_for(file_attribute)
111
+ data = data_for(file_attribute)
112
+ zipfile.get_output_stream(filename) do |f|
113
+ f.puts klass.header_fields.to_csv
114
+ data.each do |row|
115
+ f.puts row.to_csv(write_converters: klass.write_converters)
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
121
+
122
+ private
123
+
124
+ def build_manifest
125
+ new_manifest_properties = file_properties.merge(manifest_properties)
126
+ Meibo::Manifest.build_from_default(**new_manifest_properties)
127
+ end
128
+
129
+ def data_for(file_attribute)
130
+ data_method = {
131
+ file_academic_sessions: :academic_sessions,
132
+ file_classes: :classes,
133
+ file_courses: :courses,
134
+ file_demographics: :demographics,
135
+ file_enrollments: :enrollments,
136
+ file_orgs: :organizations,
137
+ file_roles: :roles,
138
+ file_user_profiles: :user_profiles,
139
+ file_users: :users
140
+ }[file_attribute]
141
+ public_send(data_method)
142
+ end
143
+
144
+ def file_properties
145
+ {
146
+ file_academic_sessions: procesing_mode(academic_sessions),
147
+ file_classes: procesing_mode(classes),
148
+ file_courses: procesing_mode(courses),
149
+ file_demographics: procesing_mode(demographics),
150
+ file_enrollments: procesing_mode(enrollments),
151
+ file_orgs: procesing_mode(organizations),
152
+ file_roles: procesing_mode(roles),
153
+ file_user_profiles: procesing_mode(user_profiles),
154
+ file_users: procesing_mode(users)
155
+ }
156
+ end
157
+
158
+ def procesing_mode(data)
159
+ if data.empty?
160
+ Meibo::Manifest::PROCESSING_MODES[:absent]
161
+ else
162
+ Meibo::Manifest::PROCESSING_MODES[:bulk]
163
+ end
164
+ end
165
+ end
166
+ end
data/lib/meibo/user.rb ADDED
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Meibo
4
+ class User
5
+ USER_ID_FORMAT_REGEXP = /\A\{[^:\}]+:[^\}]+\}\z/
6
+
7
+ DataModel.define(
8
+ self,
9
+ attribute_name_to_header_field_map: {
10
+ sourced_id: 'sourcedId',
11
+ status: 'status',
12
+ date_last_modified: 'dateLastModified',
13
+ enabled_user: 'enabledUser',
14
+ username: 'username',
15
+ user_ids: 'userIds',
16
+ given_name: 'givenName',
17
+ family_name: 'familyName',
18
+ middle_name: 'middleName',
19
+ identifier: 'identifier',
20
+ email: 'email',
21
+ sms: 'sms',
22
+ phone: 'phone',
23
+ agent_sourced_ids: 'agentSourcedIds',
24
+ grades: 'grades',
25
+ password: 'password',
26
+ user_master_identifier: 'userMasterIdentifier',
27
+ resource_sourced_ids: 'resourceSourcedIds',
28
+ preferred_given_name: 'preferredGivenName',
29
+ preferred_middle_name: 'preferredMiddleName',
30
+ preferred_family_name: 'preferredFamilyName',
31
+ primary_org_sourced_id: 'primaryOrgSourcedId',
32
+ pronouns: 'pronouns'
33
+ }.freeze,
34
+ converters: {
35
+ boolean: [:enabled_user].freeze,
36
+ datetime: [:date_last_modified].freeze,
37
+ list: [:user_ids, :agent_sourced_ids, :grades, :resource_sourced_ids].freeze,
38
+ required: [:sourced_id, :enabled_user, :username, :given_name, :family_name].freeze,
39
+ status: [:status].freeze,
40
+ user_ids: [:user_ids].freeze
41
+ }.freeze
42
+ )
43
+
44
+ def initialize(sourced_id:, status: nil, date_last_modified: nil, enabled_user: nil, username:, user_ids: nil, given_name:, family_name:, middle_name: nil, identifier: nil, email: nil, sms: nil, phone: nil, agent_sourced_ids: [], grades: nil, password: nil, user_master_identifier: nil, resource_sourced_ids: nil, preferred_given_name: nil, preferred_middle_name: nil, preferred_family_name: nil, primary_org_sourced_id: nil, pronouns: nil, kana_given_name: nil, kana_family_name: nil, kana_middle_name: nil, home_class: nil, **extension_fields)
45
+ @sourced_id = sourced_id
46
+ @status = status
47
+ @date_last_modified = date_last_modified
48
+ @enabled_user = enabled_user
49
+ @username = username
50
+ @user_ids = user_ids
51
+ @given_name = given_name
52
+ @family_name = family_name
53
+ @middle_name = middle_name
54
+ @identifier = identifier
55
+ @email = email
56
+ @sms = sms
57
+ @phone = phone
58
+ @agent_sourced_ids = agent_sourced_ids
59
+ @grades = grades
60
+ @password = password
61
+ @user_master_identifier = user_master_identifier
62
+ @resource_sourced_ids = resource_sourced_ids
63
+ @preferred_given_name = preferred_given_name
64
+ @preferred_middle_name = preferred_middle_name
65
+ @preferred_family_name = preferred_family_name
66
+ @primary_org_sourced_id = primary_org_sourced_id
67
+ @pronouns = pronouns
68
+ @extension_fields = extension_fields
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Meibo
4
+ class UserProfile
5
+ DataModel.define(
6
+ self,
7
+ attribute_name_to_header_field_map: {
8
+ sourced_id: 'sourcedId',
9
+ status: 'status',
10
+ date_last_modified: 'dateLastModified',
11
+ user_sourced_id: 'userSourcedId',
12
+ profile_type: 'profileType',
13
+ vendor_id: 'vendorId',
14
+ application_id: 'applicationId',
15
+ description: 'description',
16
+ credential_type: 'credentialType',
17
+ username: 'username',
18
+ password: 'password'
19
+ },
20
+ converters: {
21
+ datetime: [:date_last_modified],
22
+ required: [:sourced_id, :user_sourced_id, :profile_type, :vendor_id, :credential_type, :username],
23
+ status: [:status]
24
+ }
25
+ )
26
+
27
+ def initialize(sourced_id:, status: nil, date_last_modified: nil, user_sourced_id:, profile_type:, vendor_id:, application_id: nil, description: nil, credential_type:, username:, password: nil, **extension_fields)
28
+ @sourced_id = sourced_id
29
+ @status = status
30
+ @date_last_modified = date_last_modified
31
+ @user_sourced_id = user_sourced_id
32
+ @profile_type = profile_type
33
+ @vendor_id = vendor_id
34
+ @application_id = application_id
35
+ @description = description
36
+ @credential_type = credential_type
37
+ @username = username
38
+ @password = password
39
+ @extension_fields = extension_fields
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Meibo
4
+ class UserProfileSet < DataSet
5
+ def initialize(data, user_set:)
6
+ super(data)
7
+ @user_set = user_set
8
+ end
9
+
10
+ def check_semantically_consistent
11
+ super
12
+
13
+ each do |user_profile|
14
+ @user_set.find_by_sourced_id(user_profile.user_sourced_id)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Meibo
4
+ class UserSet < DataSet
5
+ def initialize(data, organization_set:)
6
+ super(data)
7
+ @organization_set = organization_set
8
+ end
9
+
10
+ def check_semantically_consistent
11
+ super
12
+
13
+ each do |user|
14
+ if user.primary_org_sourced_id
15
+ @organization_set.find_by_sourced_id(user.primary_org_sourced_id)
16
+ end
17
+
18
+ user.agent_sourced_ids.each do |agent_sourced_id|
19
+ find_by_sourced_id(agent_sourced_id)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Meibo
4
+ VERSION = "0.1.0"
5
+ end
data/lib/meibo.rb ADDED
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "zeitwerk"
4
+ loader = Zeitwerk::Loader.for_gem
5
+ loader.ignore("#{__dir__}/meibo/errors.rb")
6
+ loader.ignore("#{__dir__}/meibo/factory_bot")
7
+ loader.setup
8
+
9
+ require_relative "meibo/version"
10
+ require_relative "meibo/errors"
11
+
12
+ module Meibo
13
+ CSV_ENCODING = 'UTF-8'
14
+ ENUM_EXT_PATTERN = /\Aext:[a-zA-Z0-9\.\-_]+\z/
15
+ end
16
+
17
+ loader.eager_load
data/meibo.gemspec ADDED
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/meibo/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "meibo"
7
+ spec.version = Meibo::VERSION
8
+ spec.authors = ["Seiei Miyagi"]
9
+ spec.email = ["hanachin@gmail.com"]
10
+
11
+ spec.summary = "Meibo is a ruby library for OneRoster CSV Binding Japan Profile."
12
+ spec.homepage = "https://github.com/hanachin/meibo"
13
+ spec.license = "MIT"
14
+ spec.required_ruby_version = ">= 2.7.0"
15
+
16
+ spec.metadata["allowed_push_host"] = "https://rubygems.org/"
17
+
18
+ spec.metadata["homepage_uri"] = spec.homepage
19
+ spec.metadata["source_code_uri"] = "https://github.com/hanachin/meibo"
20
+ spec.metadata["changelog_uri"] = "https://github.com/hanachin/meibo/blob/meibo/v#{Meibo::VERSION}/CHANGELOG.md"
21
+
22
+ # Specify which files should be added to the gem when it is released.
23
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
24
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
25
+ `git ls-files -z`.split("\x0").reject do |f|
26
+ (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
27
+ end
28
+ end
29
+ spec.bindir = "exe"
30
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
31
+ spec.require_paths = ["lib"]
32
+
33
+ spec.add_dependency "rubyzip"
34
+ spec.add_dependency "zeitwerk"
35
+
36
+ # For more information and examples about making a new gem, check out our
37
+ # guide at: https://bundler.io/guides/creating_gem.html
38
+ end
data/sig/meibo.rbs ADDED
@@ -0,0 +1,4 @@
1
+ module Meibo
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,148 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: meibo
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Seiei Miyagi
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2022-11-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rubyzip
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: zeitwerk
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description:
42
+ email:
43
+ - hanachin@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".rspec"
49
+ - ".rubocop.yml"
50
+ - CHANGELOG.md
51
+ - CODE_OF_CONDUCT.md
52
+ - Gemfile
53
+ - Gemfile.lock
54
+ - LICENSE.txt
55
+ - README.md
56
+ - Rakefile
57
+ - lib/meibo.rb
58
+ - lib/meibo/academic_session.rb
59
+ - lib/meibo/academic_session_set.rb
60
+ - lib/meibo/base_profile.rb
61
+ - lib/meibo/builder.rb
62
+ - lib/meibo/builder/academic_session_builder.rb
63
+ - lib/meibo/builder/base_builder.rb
64
+ - lib/meibo/builder/classroom_builder.rb
65
+ - lib/meibo/builder/course_builder.rb
66
+ - lib/meibo/builder/demographic_builder.rb
67
+ - lib/meibo/builder/enrollment_builder.rb
68
+ - lib/meibo/builder/organization_builder.rb
69
+ - lib/meibo/builder/role_builder.rb
70
+ - lib/meibo/builder/user_builder.rb
71
+ - lib/meibo/builder/user_profile_builder.rb
72
+ - lib/meibo/classroom.rb
73
+ - lib/meibo/classroom_set.rb
74
+ - lib/meibo/converter.rb
75
+ - lib/meibo/course.rb
76
+ - lib/meibo/course_set.rb
77
+ - lib/meibo/data_model.rb
78
+ - lib/meibo/data_set.rb
79
+ - lib/meibo/demographic.rb
80
+ - lib/meibo/demographic_set.rb
81
+ - lib/meibo/enrollment.rb
82
+ - lib/meibo/enrollment_set.rb
83
+ - lib/meibo/errors.rb
84
+ - lib/meibo/factory_bot/academic_session.rb
85
+ - lib/meibo/factory_bot/all.rb
86
+ - lib/meibo/factory_bot/classroom.rb
87
+ - lib/meibo/factory_bot/course.rb
88
+ - lib/meibo/factory_bot/demographic.rb
89
+ - lib/meibo/factory_bot/enrollment.rb
90
+ - lib/meibo/factory_bot/manifest.rb
91
+ - lib/meibo/factory_bot/memory_package.rb
92
+ - lib/meibo/factory_bot/organization.rb
93
+ - lib/meibo/factory_bot/role.rb
94
+ - lib/meibo/factory_bot/user.rb
95
+ - lib/meibo/factory_bot/user_profile.rb
96
+ - lib/meibo/japan_profile.rb
97
+ - lib/meibo/japan_profile/academic_session.rb
98
+ - lib/meibo/japan_profile/classroom.rb
99
+ - lib/meibo/japan_profile/course.rb
100
+ - lib/meibo/japan_profile/demographic.rb
101
+ - lib/meibo/japan_profile/enrollment.rb
102
+ - lib/meibo/japan_profile/organization.rb
103
+ - lib/meibo/japan_profile/role.rb
104
+ - lib/meibo/japan_profile/user.rb
105
+ - lib/meibo/japan_profile/user_profile.rb
106
+ - lib/meibo/manifest.rb
107
+ - lib/meibo/manifest/processing_mode.rb
108
+ - lib/meibo/organization.rb
109
+ - lib/meibo/organization_set.rb
110
+ - lib/meibo/reader.rb
111
+ - lib/meibo/role.rb
112
+ - lib/meibo/role_set.rb
113
+ - lib/meibo/roster.rb
114
+ - lib/meibo/user.rb
115
+ - lib/meibo/user_profile.rb
116
+ - lib/meibo/user_profile_set.rb
117
+ - lib/meibo/user_set.rb
118
+ - lib/meibo/version.rb
119
+ - meibo.gemspec
120
+ - sig/meibo.rbs
121
+ homepage: https://github.com/hanachin/meibo
122
+ licenses:
123
+ - MIT
124
+ metadata:
125
+ allowed_push_host: https://rubygems.org/
126
+ homepage_uri: https://github.com/hanachin/meibo
127
+ source_code_uri: https://github.com/hanachin/meibo
128
+ changelog_uri: https://github.com/hanachin/meibo/blob/meibo/v0.1.0/CHANGELOG.md
129
+ post_install_message:
130
+ rdoc_options: []
131
+ require_paths:
132
+ - lib
133
+ required_ruby_version: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: 2.7.0
138
+ required_rubygems_version: !ruby/object:Gem::Requirement
139
+ requirements:
140
+ - - ">="
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
143
+ requirements: []
144
+ rubygems_version: 3.2.26
145
+ signing_key:
146
+ specification_version: 4
147
+ summary: Meibo is a ruby library for OneRoster CSV Binding Japan Profile.
148
+ test_files: []