duolingo_personal_data 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 90f5ce55daf9c0dddbab10bd13f36d5344e9f9cc561d5e543fa196dd2a65e545
4
- data.tar.gz: 02f08b1c773a9fb5315f5353cef2389f41dc04644d89a5c55cba3f8cdc76d1ca
3
+ metadata.gz: f1b983dd563cc933d3a549d692b2e454cba4fd0413132d93761bc874a425af91
4
+ data.tar.gz: '0497cd092c7b84103da7c1b3f9a4293386cbf157f164d8c8a5d5f9063b6daebf'
5
5
  SHA512:
6
- metadata.gz: 90bce41f9fdaf3f3d8f514929fd66d870facefe07c965d42f9c2c8c55e38b426f28fb883075462d40fcc1703f00a9af21542f9557aeaca7e3deeff557300ab40
7
- data.tar.gz: cd9de28d5e5fb51e60b87663f3fc8e0fc597074b7b0f2734b342f12985ea9829285973908db8c27c16c37b68fdaa50d64973ec4dcc2f3ca972a80a23bfd5b20e
6
+ metadata.gz: b465b8f05db11c503afa124ac232e1075bf2a7485449a5066b045b11ca77a7755000e340543f62046f82f0ffbef7c3d6872682e35e594f680e352de26ff3ff8e
7
+ data.tar.gz: 981c6cacd459875817f8e3cd10dc86c9ea209afccd83c05e2a231b41dd51e9ae1143c609811f5c7948de1968c6911896357ce878630ccb6efe73451c3140fae4
data/.rubocop.yml CHANGED
@@ -1,19 +1,19 @@
1
1
  inherit_from: .rubocop_todo.yml
2
2
 
3
+ require:
4
+ - rubocop-rake
5
+
3
6
  AllCops:
4
7
  TargetRubyVersion: 2.6
5
8
  NewCops: enable
9
+ SuggestExtensions: false # RuboCop suggests extensions even if it's installed
10
+ DisabledByDefault: true
6
11
 
7
12
  Style/StringLiterals:
8
13
  Enabled: true
9
- EnforcedStyle: double_quotes
10
14
 
11
15
  Style/StringLiteralsInInterpolation:
12
16
  Enabled: true
13
- EnforcedStyle: double_quotes
14
-
15
- Layout/LineLength:
16
- Enabled: false
17
17
 
18
18
  Style/FrozenStringLiteralComment:
19
19
  Enabled: true
data/.rubocop_todo.yml CHANGED
@@ -1,50 +1,7 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2023-03-19 06:13:02 UTC using RuboCop version 1.10.0.
3
+ # on 2023-06-18 09:30:04 UTC using RuboCop version 1.48.1.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
7
7
  # versions of RuboCop, may require this file to be generated again.
8
-
9
- # Offense count: 2
10
- # Configuration parameters: IgnoredMethods, CountRepeatedAttributes.
11
- Metrics/AbcSize:
12
- Max: 34
13
-
14
- # Offense count: 1
15
- # Configuration parameters: CountComments, CountAsOne.
16
- Metrics/ClassLength:
17
- Max: 114
18
-
19
- # Offense count: 1
20
- # Configuration parameters: IgnoredMethods.
21
- Metrics/CyclomaticComplexity:
22
- Max: 11
23
-
24
- # Offense count: 2
25
- # Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods.
26
- Metrics/MethodLength:
27
- Max: 18
28
-
29
- # Offense count: 1
30
- # Configuration parameters: IgnoredMethods.
31
- Metrics/PerceivedComplexity:
32
- Max: 11
33
-
34
- # Offense count: 12
35
- Style/Documentation:
36
- Exclude:
37
- - 'spec/**/*'
38
- - 'test/**/*'
39
- - 'lib/duolingo_personal_data/auth_data.rb'
40
- - 'lib/duolingo_personal_data/avatar_images.rb'
41
- - 'lib/duolingo_personal_data/blast_emails.rb'
42
- - 'lib/duolingo_personal_data/friends_follow.rb'
43
- - 'lib/duolingo_personal_data/inventory.rb'
44
- - 'lib/duolingo_personal_data/languages.rb'
45
- - 'lib/duolingo_personal_data/leaderboards.rb'
46
- - 'lib/duolingo_personal_data/notify_data.rb'
47
- - 'lib/duolingo_personal_data/profile.rb'
48
- - 'lib/duolingo_personal_data/stories.rb'
49
- - 'lib/duolingo_personal_data/story_completions.rb'
50
- - 'lib/duolingo_personal_data/teacher_privacy_settings.rb'
data/CHANGELOG.md CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ### Added
6
+
7
+ * Direcotry class (`DuolingoPersonalData::Direcotry`)
8
+
9
+ ### Changed, Removed, Fixed
10
+
11
+ * Changed to not delegate most Array and Hash methods
12
+ * Update RBS
13
+
14
+ ### Others
15
+
16
+ * Set RuboCop config to disable by default
17
+ * Lint with RuboCop
18
+
5
19
  ## [0.1.0] - 2023-03-19
6
20
 
7
21
  Initial release.
data/Gemfile CHANGED
@@ -1,7 +1,7 @@
1
- source "https://rubygems.org"
1
+ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
- gem "rake", "~> 13.0"
6
- gem "rubocop", "~> 1.21"
7
- gem "test-unit", "~> 3.0"
5
+ gem 'rake', '~> 13.0'
6
+ gem 'rubocop', '~> 1.21'
7
+ gem 'test-unit', '~> 3.0'
data/Rakefile CHANGED
@@ -1,22 +1,24 @@
1
- require "bundler/gem_tasks"
2
- require "rake/testtask"
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
3
 
4
4
  Rake::TestTask.new(:test) do |t|
5
- t.libs << "test"
6
- t.libs << "lib"
7
- t.test_files = FileList["test/**/*_test.rb"]
5
+ t.libs << 'test'
6
+ t.libs << 'lib'
7
+ t.test_files = FileList['test/**/*_test.rb']
8
8
  end
9
9
 
10
- require "rubocop/rake_task"
10
+ require 'rubocop/rake_task'
11
11
 
12
12
  RuboCop::RakeTask.new
13
13
 
14
14
  task default: %i[test rubocop]
15
15
 
16
+ desc 'serve generated API documentation'
16
17
  task :serve do
17
- sh "ruby -run -e httpd doc"
18
+ sh 'ruby -run -e httpd doc'
18
19
  end
19
20
 
21
+ desc 'generate type signatures'
20
22
  task :sig do
21
- sh "typeprof lib/**/* > sig/duolingo_personal_data.rbs"
23
+ sh 'typeprof lib/**/* > sig/duolingo_personal_data.rbs'
22
24
  end
@@ -1,20 +1,20 @@
1
- require_relative "lib/duolingo_personal_data/version"
1
+ require_relative 'lib/duolingo_personal_data/version'
2
2
 
3
3
  Gem::Specification.new do |spec|
4
- spec.name = "duolingo_personal_data"
4
+ spec.name = 'duolingo_personal_data'
5
5
  spec.version = DuolingoPersonalData::VERSION
6
- spec.authors = ["gemmaro"]
7
- spec.email = ["gemmaro.dev@gmail.com"]
6
+ spec.authors = ['gemmaro']
7
+ spec.email = ['gemmaro.dev@gmail.com']
8
8
 
9
- spec.summary = "Library for Duolingo personal data."
10
- spec.description = "Duolingo Personal Data gem is for loading Duolingo Personal Data, which can be acquired at <https://drive-thru.duolingo.com/>."
11
- spec.homepage = "https://gitlab.com/gemmaro/ruby-duolingo-personal-data"
12
- spec.license = "Apache-2.0"
13
- spec.required_ruby_version = ">= 2.6.0"
9
+ spec.summary = 'Library for Duolingo personal data'
10
+ spec.description = 'Duolingo Personal Data gem is for loading Duolingo Personal Data, which can be acquired at https://drive-thru.duolingo.com/.'
11
+ spec.homepage = 'https://gitlab.com/gemmaro/ruby-duolingo-personal-data'
12
+ spec.license = 'Apache-2.0'
13
+ spec.required_ruby_version = '>= 2.6.0'
14
14
 
15
- spec.metadata["homepage_uri"] = spec.homepage
16
- spec.metadata["source_code_uri"] = spec.homepage
17
- spec.metadata["changelog_uri"] = "#{spec.homepage}/-/blob/main/CHANGELOG.md"
15
+ spec.metadata['homepage_uri'] = spec.homepage
16
+ spec.metadata['source_code_uri'] = spec.homepage
17
+ spec.metadata['changelog_uri'] = "#{spec.homepage}/-/blob/main/CHANGELOG.md"
18
18
 
19
19
  spec.files = Dir.chdir(__dir__) do
20
20
  `git ls-files -z`.split("\x0").reject do |f|
@@ -22,5 +22,6 @@ Gem::Specification.new do |spec|
22
22
  end
23
23
  end
24
24
 
25
- spec.require_paths = ["lib"]
25
+ spec.require_paths = ['lib']
26
+ spec.metadata['rubygems_mfa_required'] = 'true'
26
27
  end
@@ -1,4 +1,4 @@
1
- require "csv"
1
+ require 'csv'
2
2
 
3
3
  module DuolingoPersonalData
4
4
  class AuthData
@@ -7,29 +7,29 @@ module DuolingoPersonalData
7
7
  end
8
8
 
9
9
  def user_account_name
10
- @user_account_name ||= value_from_property("User Account Name")
10
+ @user_account_name ||= value_from_property('User Account Name')
11
11
  end
12
12
 
13
13
  def email_address
14
- @email_address ||= value_from_property("Email Address")
14
+ @email_address ||= value_from_property('Email Address')
15
15
  end
16
16
 
17
17
  def last_update_timestamp
18
- @last_update_timestamp ||= value_from_property("Last Update Timestamp")
18
+ @last_update_timestamp ||= value_from_property('Last Update Timestamp')
19
19
  end
20
20
 
21
21
  def last_login_attempt_timestamp
22
- @last_login_attempt_timestamp ||= value_from_property("Last Login Attempt Timestamp")
22
+ @last_login_attempt_timestamp ||= value_from_property('Last Login Attempt Timestamp')
23
23
  end
24
24
 
25
25
  def last_authentication_key_refresh_timestamp
26
- @last_authentication_key_refresh_timestamp ||= value_from_property("Last Authentication Key Refresh Timestamp")
26
+ @last_authentication_key_refresh_timestamp ||= value_from_property('Last Authentication Key Refresh Timestamp')
27
27
  end
28
28
 
29
29
  private
30
30
 
31
31
  def value_from_property(property_name)
32
- table.find { |row| row["Property"] == property_name }["Value"]
32
+ table.find { |row| row['Property'] == property_name }['Value']
33
33
  end
34
34
 
35
35
  def table
@@ -1,6 +1,6 @@
1
- require "csv"
2
- require "uri"
3
- require "forwardable"
1
+ require 'csv'
2
+ require 'uri'
3
+ require 'forwardable'
4
4
 
5
5
  module DuolingoPersonalData
6
6
  class AvatarImages
@@ -9,12 +9,12 @@ module DuolingoPersonalData
9
9
  end
10
10
 
11
11
  extend Forwardable
12
- def_delegators :urls, *(Array.instance_methods - [:object_id])
12
+ def_delegators :urls, :to_a, :first, :size # TODO: Add more as needed
13
13
 
14
14
  private
15
15
 
16
16
  def urls
17
- @urls ||= table.map { |row| URI(row["URLs"]) }
17
+ @urls ||= table.map { |row| URI(row['URLs']) }
18
18
  end
19
19
 
20
20
  def table
@@ -1,5 +1,5 @@
1
- require "csv"
2
- require "time"
1
+ require 'csv'
2
+ require 'time'
3
3
 
4
4
  module DuolingoPersonalData
5
5
  class BlastEmails
@@ -8,60 +8,60 @@ module DuolingoPersonalData
8
8
  end
9
9
 
10
10
  def email_address
11
- @email_address ||= value_from_property("email_address")
11
+ @email_address ||= value_from_property('email_address')
12
12
  end
13
13
 
14
14
  def ui_language
15
- @ui_language ||= value_from_property("ui_language")
15
+ @ui_language ||= value_from_property('ui_language')
16
16
  end
17
17
 
18
18
  def learning_language
19
- @learning_language ||= value_from_property("learning_language")
19
+ @learning_language ||= value_from_property('learning_language')
20
20
  end
21
21
 
22
22
  def enabled
23
- @enabled ||= boolean_value_from_property("enabled")
23
+ @enabled ||= boolean_value_from_property('enabled')
24
24
  end
25
25
 
26
26
  def announcement
27
- @announcement ||= boolean_value_from_property("announcement")
27
+ @announcement ||= boolean_value_from_property('announcement')
28
28
  end
29
29
 
30
30
  def creation_datetime
31
- @creation_datetime ||= time_value_from_property("creation_datetime")
31
+ @creation_datetime ||= time_value_from_property('creation_datetime')
32
32
  end
33
33
 
34
34
  def last_session
35
- @last_session ||= time_value_from_property("last_session")
35
+ @last_session ||= time_value_from_property('last_session')
36
36
  end
37
37
 
38
38
  def trial_user
39
- @trial_user ||= boolean_value_from_property("trial_user")
39
+ @trial_user ||= boolean_value_from_property('trial_user')
40
40
  end
41
41
 
42
42
  def country
43
- @country ||= value_from_property("country")
43
+ @country ||= value_from_property('country')
44
44
  end
45
45
 
46
46
  def client
47
- @client ||= value_from_property("client")
47
+ @client ||= value_from_property('client')
48
48
  end
49
49
 
50
50
  def schools_role
51
- @schools_role ||= integer_value_from_property("schools_role")
51
+ @schools_role ||= integer_value_from_property('schools_role')
52
52
  end
53
53
 
54
54
  private
55
55
 
56
56
  def value_from_property(property_name)
57
- table.find { |row| row["property"] == property_name }["value"]
57
+ table.find { |row| row['property'] == property_name }['value']
58
58
  end
59
59
 
60
60
  def boolean_value_from_property(property_name)
61
61
  value = value_from_property(property_name)
62
62
  case value
63
- when "0" then false
64
- when "1" then true
63
+ when '0' then false
64
+ when '1' then true
65
65
  else
66
66
  raise Error, "cannot interpret #{value.inspect} as boolean"
67
67
  end
@@ -69,7 +69,7 @@ module DuolingoPersonalData
69
69
 
70
70
  def time_value_from_property(property_name)
71
71
  value = value_from_property(property_name)
72
- Time.strptime(value, "%Y-%m-%d %T")
72
+ Time.strptime(value, '%Y-%m-%d %T')
73
73
  end
74
74
 
75
75
  def integer_value_from_property(property_name)
@@ -0,0 +1,55 @@
1
+ module DuolingoPersonalData
2
+ class Directory
3
+ def initialize(path)
4
+ @path = path
5
+ end
6
+
7
+ def auth_data
8
+ @auth_data ||= AuthData.new(File.join(@path, 'auth_data.csv'))
9
+ end
10
+
11
+ def avatar_images
12
+ @avatar_images ||= AvatarImages.new(File.join(@path, 'avatar_images.csv'))
13
+ end
14
+
15
+ def blast_emails
16
+ @blast_emails ||= BlastEmails.new(File.join(@path, 'duolingo-blast-emails.csv'))
17
+ end
18
+
19
+ def notify_data
20
+ @notify_data ||= NotifyData.new(File.join(@path, 'duolingo-notify-data.csv'))
21
+ end
22
+
23
+ def friends_follow
24
+ @friends_follow ||= FriendsFollow.new(File.join(@path, 'friends-follow.csv'))
25
+ end
26
+
27
+ def inventory
28
+ @inventory ||= Inventory.new(File.join(@path, 'inventory.csv'))
29
+ end
30
+
31
+ def languages
32
+ @languages ||= Languages.new(File.join(@path, 'languages.csv'))
33
+ end
34
+
35
+ def leaderboards
36
+ @leaderboards ||= Leaderboards.new(File.join(@path, 'leaderboards.csv'))
37
+ end
38
+
39
+ def profile
40
+ @profile ||= Profile.new(File.join(@path, 'profile.csv'))
41
+ end
42
+
43
+ def stories
44
+ @stories ||= Stories.new(File.join(@path, 'stories.csv'))
45
+ end
46
+
47
+ def story_completions
48
+ @story_completions ||= StoryCompletions.new(File.join(@path, 'stories-story-completions.csv'))
49
+ end
50
+
51
+ def teacher_privacy_settings
52
+ @teacher_privacy_settings ||= TeacherPrivacySettings.new(File.join(@path, 'TeacherPrivacySettings.csv'))
53
+ end
54
+ end
55
+ end
@@ -5,23 +5,23 @@ module DuolingoPersonalData
5
5
  end
6
6
 
7
7
  def num_following
8
- @num_following ||= integer_value_from_property("num_following")
8
+ @num_following ||= integer_value_from_property('num_following')
9
9
  end
10
10
 
11
11
  def num_followers
12
- @num_followers ||= integer_value_from_property("num_followers")
12
+ @num_followers ||= integer_value_from_property('num_followers')
13
13
  end
14
14
 
15
15
  def num_blocking
16
- @num_blocking ||= integer_value_from_property("num_blocking")
16
+ @num_blocking ||= integer_value_from_property('num_blocking')
17
17
  end
18
18
 
19
19
  def num_blockers
20
- @num_blockers ||= integer_value_from_property("num_blockers")
20
+ @num_blockers ||= integer_value_from_property('num_blockers')
21
21
  end
22
22
 
23
23
  def timestamp_generated
24
- @timestamp_generated ||= timestamp_value_from_property("timestamp_generated")
24
+ @timestamp_generated ||= timestamp_value_from_property('timestamp_generated')
25
25
  end
26
26
 
27
27
  private
@@ -1,4 +1,4 @@
1
- require "forwardable"
1
+ require 'forwardable'
2
2
 
3
3
  module DuolingoPersonalData
4
4
  InventoryItem = Struct.new(:item_type, :purchase_datetime, :active, :price_in_virtual_currency, :wager_day,
@@ -10,32 +10,32 @@ module DuolingoPersonalData
10
10
  end
11
11
 
12
12
  extend Forwardable
13
- def_delegators :items, *(Array.instance_methods - [:object_id])
13
+ def_delegators :items, :to_a, :first, :size, :[] # TODO: Add more as needed
14
14
 
15
15
  private
16
16
 
17
17
  def items
18
18
  @items ||= table.map do |row|
19
- item = InventoryItem.new(item_type: row["item_type"],
20
- purchase_datetime: parse_datetime(row["purchase_datetime"]), active: parse_boolean(row["active"]), payment_processor: row["payment_processor"], product: row["product"])
21
- price = row["price_in_virtual_currency"]
19
+ item = InventoryItem.new(item_type: row['item_type'],
20
+ purchase_datetime: parse_datetime(row['purchase_datetime']), active: parse_boolean(row['active']), payment_processor: row['payment_processor'], product: row['product'])
21
+ price = row['price_in_virtual_currency']
22
22
  item.price_in_virtual_currency = Integer(price) if price
23
- day = row["wager_day"]
23
+ day = row['wager_day']
24
24
  item.wager_day = Integer(day) if day
25
- expiration = row["expected_expiration"]
25
+ expiration = row['expected_expiration']
26
26
  item.expected_expiration = parse_datetime(expiration) if expiration
27
27
  item
28
28
  end
29
29
  end
30
30
 
31
31
  def parse_datetime(str)
32
- Time.strptime(str, "%Y-%m-%d %T")
32
+ Time.strptime(str, '%Y-%m-%d %T')
33
33
  end
34
34
 
35
35
  def parse_boolean(str)
36
36
  case str
37
- when "false" then false
38
- when "true" then true
37
+ when 'false' then false
38
+ when 'true' then true
39
39
  else
40
40
  raise Error, "cannot parse #{str.inspect} as boolean"
41
41
  end
@@ -1,5 +1,5 @@
1
- require "forwardable"
2
- require "csv"
1
+ require 'forwardable'
2
+ require 'csv'
3
3
 
4
4
  module DuolingoPersonalData
5
5
  Language = Struct.new(:from_language, :points, :skill_learned, :total_lessons, :days_active, :last_active,
@@ -10,33 +10,33 @@ module DuolingoPersonalData
10
10
  end
11
11
 
12
12
  extend Forwardable
13
- def_delegators :languages, *(Hash.instance_methods - [:object_id])
13
+ def_delegators :languages, :to_h, :[] # TODO: Add more as needed
14
14
 
15
15
  private
16
16
 
17
17
  def languages
18
18
  @languages ||= CSV.read(@csv_path, headers: true).map do |row|
19
- language = Language.new(from_language: row["from_language"])
20
- points = row["points"]
19
+ language = Language.new(from_language: row['from_language'])
20
+ points = row['points']
21
21
  language.points = Integer(points) if points
22
- skills = row["skills_learned"]
22
+ skills = row['skills_learned']
23
23
  language.skill_learned = Integer(skills) if skills
24
- lessons = row["total_lessons"]
24
+ lessons = row['total_lessons']
25
25
  language.total_lessons = Integer(lessons) if lessons
26
- days = row["days_active"]
26
+ days = row['days_active']
27
27
  language.days_active = Integer(days) if days
28
- active = row["last_active"]
28
+ active = row['last_active']
29
29
  language.last_active = parse_datetime(active) if active
30
- proficiency = row["prior_proficiency"]
30
+ proficiency = row['prior_proficiency']
31
31
  language.prior_proficiency = Integer(proficiency) if proficiency
32
- subscribed = row["subscribed"]
32
+ subscribed = row['subscribed']
33
33
  language.subscribed = parse_datetime(subscribed) if subscribed
34
- { row["learning_language"] => language }
34
+ { row['learning_language'] => language }
35
35
  end.reduce(&:merge)
36
36
  end
37
37
 
38
38
  def parse_datetime(str)
39
- Time.strptime(str, "%Y-%m-%d %T")
39
+ Time.strptime(str, '%Y-%m-%d %T')
40
40
  end
41
41
  end
42
42
  end
@@ -1,5 +1,5 @@
1
- require "csv"
2
- require "forwardable"
1
+ require 'csv'
2
+ require 'forwardable'
3
3
 
4
4
  module DuolingoPersonalData
5
5
  LeaderboardsEntry = Struct.new(:timestamp, :tier, :score, keyword_init: true)
@@ -10,14 +10,14 @@ module DuolingoPersonalData
10
10
  end
11
11
 
12
12
  extend Forwardable
13
- def_delegators :leaderboards_entries, *(Array.instance_methods - [:object_id])
13
+ def_delegators :leaderboards_entries, :to_a, :first, :size, :[] # TODO: Add more as needed
14
14
 
15
15
  private
16
16
 
17
17
  def leaderboards_entries
18
18
  @leaderboards_entries ||= CSV.read(@csv_path, headers: true).map do |row|
19
- LeaderboardsEntry.new(timestamp: Time.strptime(row["timestamp"], "%FT%TZ"), tier: Integer(row["tier"]),
20
- score: Float(row["score"]))
19
+ LeaderboardsEntry.new(timestamp: Time.strptime(row['timestamp'], '%FT%TZ'), tier: Integer(row['tier']),
20
+ score: Float(row['score']))
21
21
  end
22
22
  end
23
23
  end
@@ -1,4 +1,4 @@
1
- require "json"
1
+ require 'json'
2
2
 
3
3
  module DuolingoPersonalData
4
4
  class NotifyData
@@ -7,17 +7,17 @@ module DuolingoPersonalData
7
7
  end
8
8
 
9
9
  def email
10
- @email ||= value_from_property("email")
10
+ @email ||= value_from_property('email')
11
11
  end
12
12
 
13
13
  def device_ids
14
- @device_ids ||= json_value_from_property("device_ids")
14
+ @device_ids ||= json_value_from_property('device_ids')
15
15
  end
16
16
 
17
17
  private
18
18
 
19
19
  def value_from_property(property_name)
20
- table.find { |row| row["property"] == property_name }["value"]
20
+ table.find { |row| row['property'] == property_name }['value']
21
21
  end
22
22
 
23
23
  def json_value_from_property(property_name)
@@ -1,4 +1,4 @@
1
- require "csv"
1
+ require 'csv'
2
2
 
3
3
  module DuolingoPersonalData
4
4
  class Profile
@@ -7,49 +7,49 @@ module DuolingoPersonalData
7
7
  end
8
8
 
9
9
  def username
10
- @username ||= value_from_property("username")
10
+ @username ||= value_from_property('username')
11
11
  end
12
12
 
13
13
  def email
14
- @email ||= value_from_property("email")
14
+ @email ||= value_from_property('email')
15
15
  end
16
16
 
17
17
  def fullname
18
- @fullname ||= value_from_property("fullname")
18
+ @fullname ||= value_from_property('fullname')
19
19
  end
20
20
 
21
21
  def joined_at
22
- @joined_at ||= datetime_value_from_property("joined_at")
22
+ @joined_at ||= datetime_value_from_property('joined_at')
23
23
  end
24
24
 
25
25
  def ui_language
26
- @ui_language ||= value_from_property("ui_language")
26
+ @ui_language ||= value_from_property('ui_language')
27
27
  end
28
28
 
29
29
  def learning_language
30
- @learning_language ||= value_from_property("learning_language")
30
+ @learning_language ||= value_from_property('learning_language')
31
31
  end
32
32
 
33
33
  def lingots
34
- @lingots ||= integer_value_from_property("lingots")
34
+ @lingots ||= integer_value_from_property('lingots')
35
35
  end
36
36
 
37
37
  def daily_goal
38
- @daily_goal ||= integer_value_from_property("daily_goal")
38
+ @daily_goal ||= integer_value_from_property('daily_goal')
39
39
  end
40
40
 
41
41
  def timezone
42
- @timezone ||= value_from_property("timezone")
42
+ @timezone ||= value_from_property('timezone')
43
43
  end
44
44
 
45
45
  def avatar_url
46
- @avatar_url ||= value_from_property("avatar_url")
46
+ @avatar_url ||= value_from_property('avatar_url')
47
47
  end
48
48
 
49
49
  private
50
50
 
51
51
  def value_from_property(property_name)
52
- table.find { |row| row["name"] == property_name }["value"]
52
+ table.find { |row| row['name'] == property_name }['value']
53
53
  end
54
54
 
55
55
  def integer_value_from_property(property_name)
@@ -57,7 +57,7 @@ module DuolingoPersonalData
57
57
  end
58
58
 
59
59
  def datetime_value_from_property(property_name)
60
- Time.strptime(value_from_property(property_name), "%F %T")
60
+ Time.strptime(value_from_property(property_name), '%F %T')
61
61
  end
62
62
 
63
63
  def table
@@ -5,11 +5,11 @@ module DuolingoPersonalData
5
5
  end
6
6
 
7
7
  def user_id
8
- @user_id ||= value_from_property("userId")
8
+ @user_id ||= value_from_property('userId')
9
9
  end
10
10
 
11
11
  def date_of_first_visit_to_stories
12
- @date_of_first_visit_to_stories ||= datetime_value_from_property("dateOfFirstVisitToStories")
12
+ @date_of_first_visit_to_stories ||= datetime_value_from_property('dateOfFirstVisitToStories')
13
13
  end
14
14
 
15
15
  private
@@ -19,7 +19,7 @@ module DuolingoPersonalData
19
19
  end
20
20
 
21
21
  def datetime_value_from_property(property_name)
22
- Time.strptime(value_from_property(property_name), "%F %T")
22
+ Time.strptime(value_from_property(property_name), '%F %T')
23
23
  end
24
24
 
25
25
  def table
@@ -1,4 +1,4 @@
1
- require "forwardable"
1
+ require 'forwardable'
2
2
 
3
3
  module DuolingoPersonalData
4
4
  StoryCompletion = Struct.new(:user_id, :story_id, :score, :time, keyword_init: true)
@@ -9,14 +9,14 @@ module DuolingoPersonalData
9
9
  end
10
10
 
11
11
  extend Forwardable
12
- def_delegators :completions, *(Array.instance_methods - [:object_id])
12
+ def_delegators :completions, :[] # TODO: Add more as needed
13
13
 
14
14
  private
15
15
 
16
16
  def completions
17
17
  @completions ||= CSV.read(@csv_path, headers: true).map do |row|
18
- StoryCompletion.new(user_id: row["userId"], story_id: row["storyId"], score: Integer(row["score"]),
19
- time: Time.strptime(row["time"], "%F %T"))
18
+ StoryCompletion.new(user_id: row['userId'], story_id: row['storyId'], score: Integer(row['score']),
19
+ time: Time.strptime(row['time'], '%F %T'))
20
20
  end
21
21
  end
22
22
  end
@@ -5,27 +5,27 @@ module DuolingoPersonalData
5
5
  end
6
6
 
7
7
  def disable_clubs
8
- @disable_clubs ||= boolean_value_from_property("disable_clubs")
8
+ @disable_clubs ||= boolean_value_from_property('disable_clubs')
9
9
  end
10
10
 
11
11
  def disable_discussions
12
- @disable_discussions ||= boolean_value_from_property("disable_discussions")
12
+ @disable_discussions ||= boolean_value_from_property('disable_discussions')
13
13
  end
14
14
 
15
15
  def disable_events
16
- @disable_events ||= boolean_value_from_property("disable_events")
16
+ @disable_events ||= boolean_value_from_property('disable_events')
17
17
  end
18
18
 
19
19
  def disable_stream
20
- @disable_stream ||= boolean_value_from_property("disable_stream")
20
+ @disable_stream ||= boolean_value_from_property('disable_stream')
21
21
  end
22
22
 
23
23
  def disable_immersion
24
- @disable_immersion ||= boolean_value_from_property("disable_immersion")
24
+ @disable_immersion ||= boolean_value_from_property('disable_immersion')
25
25
  end
26
26
 
27
27
  def disable_mature_words
28
- @disable_mature_words ||= boolean_value_from_property("disable_mature_words")
28
+ @disable_mature_words ||= boolean_value_from_property('disable_mature_words')
29
29
  end
30
30
 
31
31
  private
@@ -33,8 +33,8 @@ module DuolingoPersonalData
33
33
  def boolean_value_from_property(property_name)
34
34
  value = value_from_property(property_name)
35
35
  case value
36
- when "False" then false
37
- when "True" then true
36
+ when 'False' then false
37
+ when 'True' then true
38
38
  else
39
39
  raise Error, "cannot interpret #{value.inspect} as boolean"
40
40
  end
@@ -1,3 +1,3 @@
1
1
  module DuolingoPersonalData
2
- VERSION = "0.1.0".freeze
2
+ VERSION = '0.2.0'
3
3
  end
@@ -1,16 +1,17 @@
1
- require_relative "duolingo_personal_data/version"
2
- require_relative "duolingo_personal_data/auth_data"
3
- require_relative "duolingo_personal_data/avatar_images"
4
- require_relative "duolingo_personal_data/blast_emails"
5
- require_relative "duolingo_personal_data/notify_data"
6
- require_relative "duolingo_personal_data/friends_follow"
7
- require_relative "duolingo_personal_data/inventory"
8
- require_relative "duolingo_personal_data/languages"
9
- require_relative "duolingo_personal_data/leaderboards"
10
- require_relative "duolingo_personal_data/profile"
11
- require_relative "duolingo_personal_data/stories"
12
- require_relative "duolingo_personal_data/story_completions"
13
- require_relative "duolingo_personal_data/teacher_privacy_settings"
1
+ require_relative 'duolingo_personal_data/version'
2
+ require_relative 'duolingo_personal_data/auth_data'
3
+ require_relative 'duolingo_personal_data/avatar_images'
4
+ require_relative 'duolingo_personal_data/blast_emails'
5
+ require_relative 'duolingo_personal_data/notify_data'
6
+ require_relative 'duolingo_personal_data/friends_follow'
7
+ require_relative 'duolingo_personal_data/inventory'
8
+ require_relative 'duolingo_personal_data/languages'
9
+ require_relative 'duolingo_personal_data/leaderboards'
10
+ require_relative 'duolingo_personal_data/profile'
11
+ require_relative 'duolingo_personal_data/stories'
12
+ require_relative 'duolingo_personal_data/story_completions'
13
+ require_relative 'duolingo_personal_data/teacher_privacy_settings'
14
+ require_relative 'duolingo_personal_data/directory'
14
15
 
15
16
  module DuolingoPersonalData
16
17
  class Error < StandardError; end
data/manifest.scm CHANGED
@@ -1,3 +1,3 @@
1
1
  (use-modules (gnu packages ruby))
2
2
 
3
- (packages->manifest (list ruby-rubocop ruby))
3
+ (packages->manifest (list ruby-rubocop ruby-rubocop-rake ruby bundler))
@@ -5,7 +5,7 @@ module DuolingoPersonalData
5
5
  VERSION: String
6
6
 
7
7
  class AuthData
8
- @csv_path: untyped
8
+ @csv_path: String
9
9
  @user_account_name: String?
10
10
  @table: Array[Array[String?]]
11
11
  @email_address: String?
@@ -13,7 +13,7 @@ module DuolingoPersonalData
13
13
  @last_login_attempt_timestamp: String?
14
14
  @last_authentication_key_refresh_timestamp: String?
15
15
 
16
- def initialize: (untyped csv_path) -> void
16
+ def initialize: (String csv_path) -> void
17
17
  def user_account_name: -> String?
18
18
  def email_address: -> String?
19
19
  def last_update_timestamp: -> String?
@@ -27,11 +27,11 @@ module DuolingoPersonalData
27
27
 
28
28
  class AvatarImages
29
29
  extend Forwardable
30
- @csv_path: untyped
30
+ @csv_path: String
31
31
  @urls: Array[URI::Generic]
32
32
  @table: Array[Array[String?]]
33
33
 
34
- def initialize: (untyped csv_path) -> void
34
+ def initialize: (String csv_path) -> void
35
35
 
36
36
  private
37
37
  def urls: -> Array[URI::Generic]
@@ -39,7 +39,7 @@ module DuolingoPersonalData
39
39
  end
40
40
 
41
41
  class BlastEmails
42
- @csv_path: untyped
42
+ @csv_path: String
43
43
  @email_address: String?
44
44
  @table: Array[Array[String?]]
45
45
  @ui_language: String?
@@ -53,7 +53,7 @@ module DuolingoPersonalData
53
53
  @client: String?
54
54
  @schools_role: Integer
55
55
 
56
- def initialize: (untyped csv_path) -> void
56
+ def initialize: (String csv_path) -> void
57
57
  def email_address: -> String?
58
58
  def ui_language: -> String?
59
59
  def learning_language: -> String?
@@ -74,6 +74,36 @@ module DuolingoPersonalData
74
74
  def table: -> Array[Array[String?]]
75
75
  end
76
76
 
77
+ class Directory
78
+ @path: untyped
79
+ @auth_data: AuthData
80
+ @avatar_images: AvatarImages
81
+ @blast_emails: BlastEmails
82
+ @notify_data: untyped
83
+ @friends_follow: untyped
84
+ @inventory: untyped
85
+ @languages: untyped
86
+ @leaderboards: untyped
87
+ @profile: untyped
88
+ @stories: untyped
89
+ @story_completions: untyped
90
+ @teacher_privacy_settings: untyped
91
+
92
+ def initialize: (untyped path) -> void
93
+ def auth_data: -> AuthData
94
+ def avatar_images: -> AvatarImages
95
+ def blast_emails: -> BlastEmails
96
+ def notify_data: -> untyped
97
+ def friends_follow: -> untyped
98
+ def inventory: -> untyped
99
+ def languages: -> untyped
100
+ def leaderboards: -> untyped
101
+ def profile: -> untyped
102
+ def stories: -> untyped
103
+ def story_completions: -> untyped
104
+ def teacher_privacy_settings: -> untyped
105
+ end
106
+
77
107
  class FriendsFollow
78
108
  @csv_path: untyped
79
109
  @num_following: Integer
@@ -155,12 +185,12 @@ module DuolingoPersonalData
155
185
  class Leaderboards
156
186
  extend Forwardable
157
187
  @csv_path: untyped
158
- @entries: Array[LeaderboardsEntry]
188
+ @leaderboards_entries: Array[LeaderboardsEntry]
159
189
 
160
190
  def initialize: (untyped csv_path) -> void
161
191
 
162
192
  private
163
- def entries: -> Array[LeaderboardsEntry]
193
+ def leaderboards_entries: -> Array[LeaderboardsEntry]
164
194
  end
165
195
 
166
196
  class NotifyData
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: duolingo_personal_data
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - gemmaro
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-03-19 00:00:00.000000000 Z
11
+ date: 2023-06-18 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Duolingo Personal Data gem is for loading Duolingo Personal Data, which
14
- can be acquired at <https://drive-thru.duolingo.com/>.
14
+ can be acquired at https://drive-thru.duolingo.com/.
15
15
  email:
16
16
  - gemmaro.dev@gmail.com
17
17
  executables: []
@@ -42,6 +42,7 @@ files:
42
42
  - lib/duolingo_personal_data/auth_data.rb
43
43
  - lib/duolingo_personal_data/avatar_images.rb
44
44
  - lib/duolingo_personal_data/blast_emails.rb
45
+ - lib/duolingo_personal_data/directory.rb
45
46
  - lib/duolingo_personal_data/friends_follow.rb
46
47
  - lib/duolingo_personal_data/inventory.rb
47
48
  - lib/duolingo_personal_data/languages.rb
@@ -61,6 +62,7 @@ metadata:
61
62
  homepage_uri: https://gitlab.com/gemmaro/ruby-duolingo-personal-data
62
63
  source_code_uri: https://gitlab.com/gemmaro/ruby-duolingo-personal-data
63
64
  changelog_uri: https://gitlab.com/gemmaro/ruby-duolingo-personal-data/-/blob/main/CHANGELOG.md
65
+ rubygems_mfa_required: 'true'
64
66
  post_install_message:
65
67
  rdoc_options: []
66
68
  require_paths:
@@ -79,5 +81,5 @@ requirements: []
79
81
  rubygems_version: 3.1.6
80
82
  signing_key:
81
83
  specification_version: 4
82
- summary: Library for Duolingo personal data.
84
+ summary: Library for Duolingo personal data
83
85
  test_files: []