kinopoisk_unofficial_api 1.0.0.1

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 (105) hide show
  1. checksums.yaml +7 -0
  2. data/.env.example +1 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +23 -0
  5. data/CHANGELOG.md +3 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +185 -0
  8. data/Rakefile +17 -0
  9. data/data/countries.json +1002 -0
  10. data/data/genres.json +134 -0
  11. data/data/type_attributes.json +1589 -0
  12. data/lib/kinopoisk_unofficial_api/client.rb +67 -0
  13. data/lib/kinopoisk_unofficial_api/configuration.rb +15 -0
  14. data/lib/kinopoisk_unofficial_api/endpoints.rb +139 -0
  15. data/lib/kinopoisk_unofficial_api/exceptions/base.rb +7 -0
  16. data/lib/kinopoisk_unofficial_api/exceptions/response_error.rb +37 -0
  17. data/lib/kinopoisk_unofficial_api/request_schemas/api_key.rb +9 -0
  18. data/lib/kinopoisk_unofficial_api/request_schemas/base.rb +17 -0
  19. data/lib/kinopoisk_unofficial_api/request_schemas/film.rb +11 -0
  20. data/lib/kinopoisk_unofficial_api/request_schemas/film_awards.rb +7 -0
  21. data/lib/kinopoisk_unofficial_api/request_schemas/film_box_office.rb +7 -0
  22. data/lib/kinopoisk_unofficial_api/request_schemas/film_collections.rb +29 -0
  23. data/lib/kinopoisk_unofficial_api/request_schemas/film_distributions.rb +7 -0
  24. data/lib/kinopoisk_unofficial_api/request_schemas/film_external_sources.rb +9 -0
  25. data/lib/kinopoisk_unofficial_api/request_schemas/film_facts.rb +7 -0
  26. data/lib/kinopoisk_unofficial_api/request_schemas/film_images.rb +24 -0
  27. data/lib/kinopoisk_unofficial_api/request_schemas/film_premieres.rb +25 -0
  28. data/lib/kinopoisk_unofficial_api/request_schemas/film_reviews.rb +21 -0
  29. data/lib/kinopoisk_unofficial_api/request_schemas/film_seasons.rb +7 -0
  30. data/lib/kinopoisk_unofficial_api/request_schemas/film_sequels_and_prequels.rb +7 -0
  31. data/lib/kinopoisk_unofficial_api/request_schemas/film_similars.rb +7 -0
  32. data/lib/kinopoisk_unofficial_api/request_schemas/film_staff.rb +11 -0
  33. data/lib/kinopoisk_unofficial_api/request_schemas/film_videos.rb +7 -0
  34. data/lib/kinopoisk_unofficial_api/request_schemas/films.rb +84 -0
  35. data/lib/kinopoisk_unofficial_api/request_schemas/kp_user_votes.rb +12 -0
  36. data/lib/kinopoisk_unofficial_api/request_schemas/media_posts.rb +9 -0
  37. data/lib/kinopoisk_unofficial_api/request_schemas/persons.rb +10 -0
  38. data/lib/kinopoisk_unofficial_api/request_schemas/search_film_by_keyword.rb +10 -0
  39. data/lib/kinopoisk_unofficial_api/request_schemas/staff.rb +11 -0
  40. data/lib/kinopoisk_unofficial_api/request_schemas.rb +7 -0
  41. data/lib/kinopoisk_unofficial_api/types/api_key_response/daily_quota.rb +12 -0
  42. data/lib/kinopoisk_unofficial_api/types/api_key_response/total_quota.rb +12 -0
  43. data/lib/kinopoisk_unofficial_api/types/api_key_response.rb +11 -0
  44. data/lib/kinopoisk_unofficial_api/types/award.rb +14 -0
  45. data/lib/kinopoisk_unofficial_api/types/award_person.rb +21 -0
  46. data/lib/kinopoisk_unofficial_api/types/award_response.rb +10 -0
  47. data/lib/kinopoisk_unofficial_api/types/base.rb +14 -0
  48. data/lib/kinopoisk_unofficial_api/types/box_office.rb +13 -0
  49. data/lib/kinopoisk_unofficial_api/types/box_office_response.rb +10 -0
  50. data/lib/kinopoisk_unofficial_api/types/compactable.rb +19 -0
  51. data/lib/kinopoisk_unofficial_api/types/company.rb +9 -0
  52. data/lib/kinopoisk_unofficial_api/types/country.rb +9 -0
  53. data/lib/kinopoisk_unofficial_api/types/digital_release_item.rb +22 -0
  54. data/lib/kinopoisk_unofficial_api/types/digital_release_response.rb +11 -0
  55. data/lib/kinopoisk_unofficial_api/types/distribution.rb +14 -0
  56. data/lib/kinopoisk_unofficial_api/types/distribution_response.rb +10 -0
  57. data/lib/kinopoisk_unofficial_api/types/episode.rb +14 -0
  58. data/lib/kinopoisk_unofficial_api/types/external_source_response/item.rb +18 -0
  59. data/lib/kinopoisk_unofficial_api/types/external_source_response.rb +10 -0
  60. data/lib/kinopoisk_unofficial_api/types/fact.rb +11 -0
  61. data/lib/kinopoisk_unofficial_api/types/fact_response.rb +10 -0
  62. data/lib/kinopoisk_unofficial_api/types/film.rb +53 -0
  63. data/lib/kinopoisk_unofficial_api/types/film_collection_response/item.rb +22 -0
  64. data/lib/kinopoisk_unofficial_api/types/film_collection_response.rb +11 -0
  65. data/lib/kinopoisk_unofficial_api/types/film_search_by_filters_response/item.rb +23 -0
  66. data/lib/kinopoisk_unofficial_api/types/film_search_by_filters_response.rb +11 -0
  67. data/lib/kinopoisk_unofficial_api/types/film_search_response/film.rb +23 -0
  68. data/lib/kinopoisk_unofficial_api/types/film_search_response.rb +12 -0
  69. data/lib/kinopoisk_unofficial_api/types/film_sequels_and_prequels_response.rb +15 -0
  70. data/lib/kinopoisk_unofficial_api/types/filters_response/country.rb +12 -0
  71. data/lib/kinopoisk_unofficial_api/types/filters_response/genre.rb +12 -0
  72. data/lib/kinopoisk_unofficial_api/types/filters_response.rb +10 -0
  73. data/lib/kinopoisk_unofficial_api/types/genre.rb +9 -0
  74. data/lib/kinopoisk_unofficial_api/types/image_response/item.rb +12 -0
  75. data/lib/kinopoisk_unofficial_api/types/image_response.rb +11 -0
  76. data/lib/kinopoisk_unofficial_api/types/kinopoisk_user_vote_response/item.rb +23 -0
  77. data/lib/kinopoisk_unofficial_api/types/kinopoisk_user_vote_response.rb +11 -0
  78. data/lib/kinopoisk_unofficial_api/types/media_posts_response/item.rb +16 -0
  79. data/lib/kinopoisk_unofficial_api/types/media_posts_response.rb +11 -0
  80. data/lib/kinopoisk_unofficial_api/types/pattern_matching.rb +11 -0
  81. data/lib/kinopoisk_unofficial_api/types/person_by_name_response/item.rb +16 -0
  82. data/lib/kinopoisk_unofficial_api/types/person_by_name_response.rb +10 -0
  83. data/lib/kinopoisk_unofficial_api/types/person_response/film.rb +17 -0
  84. data/lib/kinopoisk_unofficial_api/types/person_response/spouse.rb +18 -0
  85. data/lib/kinopoisk_unofficial_api/types/person_response.rb +25 -0
  86. data/lib/kinopoisk_unofficial_api/types/premiere_response.rb +10 -0
  87. data/lib/kinopoisk_unofficial_api/types/premiere_response_item.rb +18 -0
  88. data/lib/kinopoisk_unofficial_api/types/related_film_response/item.rb +17 -0
  89. data/lib/kinopoisk_unofficial_api/types/related_film_response.rb +10 -0
  90. data/lib/kinopoisk_unofficial_api/types/review_response/item.rb +18 -0
  91. data/lib/kinopoisk_unofficial_api/types/review_response.rb +14 -0
  92. data/lib/kinopoisk_unofficial_api/types/season.rb +10 -0
  93. data/lib/kinopoisk_unofficial_api/types/season_response.rb +10 -0
  94. data/lib/kinopoisk_unofficial_api/types/staff_response.rb +15 -0
  95. data/lib/kinopoisk_unofficial_api/types/video_response/item.rb +13 -0
  96. data/lib/kinopoisk_unofficial_api/types/video_response.rb +10 -0
  97. data/lib/kinopoisk_unofficial_api/types.rb +7 -0
  98. data/lib/kinopoisk_unofficial_api/version.rb +5 -0
  99. data/lib/kinopoisk_unofficial_api.rb +25 -0
  100. data/rakelib/parse_schema.rake +103 -0
  101. data/rakelib/rebuild_types.rake +105 -0
  102. data/rakelib/templates/empty_type.erb +12 -0
  103. data/rakelib/templates/nested_type.erb +13 -0
  104. data/rakelib/templates/type.erb +11 -0
  105. metadata +188 -0
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KinopoiskUnofficialApi
4
+ module Types
5
+ class PersonResponse < Base
6
+ class Film < Base
7
+ attribute? :film_id, Types::Integer
8
+ attribute? :name_ru, Types::String.optional
9
+ attribute? :name_en, Types::String.optional
10
+ attribute? :rating, Types::String.optional
11
+ attribute? :general, Types::Bool
12
+ attribute? :description, Types::String.optional
13
+ attribute? :profession_key, Types::String
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KinopoiskUnofficialApi
4
+ module Types
5
+ class PersonResponse < Base
6
+ class Spouse < Base
7
+ attribute? :person_id, Types::Integer
8
+ attribute? :name, Types::String.optional
9
+ attribute? :divorced, Types::Bool
10
+ attribute? :divorced_reason, Types::String.optional
11
+ attribute? :sex, Types::String
12
+ attribute? :children, Types::Integer
13
+ attribute? :web_url, Types::String
14
+ attribute? :relation, Types::String
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KinopoiskUnofficialApi
4
+ module Types
5
+ class PersonResponse < Base
6
+ attribute :person_id, Types::Integer
7
+ attribute :web_url, Types::String.optional
8
+ attribute :name_ru, Types::String.optional
9
+ attribute :name_en, Types::String.optional
10
+ attribute :sex, Types::String.optional
11
+ attribute :poster_url, Types::String
12
+ attribute :growth, Types::Integer.optional
13
+ attribute :birthday, Types::String.optional
14
+ attribute :death, Types::String.optional
15
+ attribute :age, Types::Integer.optional
16
+ attribute :birthplace, Types::String.optional
17
+ attribute :deathplace, Types::String.optional
18
+ attribute :has_awards, Types::Integer.optional
19
+ attribute :profession, Types::String.optional
20
+ attribute :facts, Types::Array.of(Types::String)
21
+ attribute :spouses, Types::Array.of(PersonResponse::Spouse)
22
+ attribute :films, Types::Array.of(PersonResponse::Film)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KinopoiskUnofficialApi
4
+ module Types
5
+ class PremiereResponse < Base
6
+ attribute :total, Types::Integer
7
+ attribute :items, Types::Array.of(PremiereResponseItem)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KinopoiskUnofficialApi
4
+ module Types
5
+ class PremiereResponseItem < Base
6
+ attribute :kinopoisk_id, Types::Integer
7
+ attribute :name_ru, Types::String.optional
8
+ attribute :name_en, Types::String.optional
9
+ attribute :year, Types::Integer
10
+ attribute :poster_url, Types::String
11
+ attribute :poster_url_preview, Types::String
12
+ attribute :countries, Types::Array.of(Country)
13
+ attribute :genres, Types::Array.of(Genre)
14
+ attribute :duration, Types::Integer.optional
15
+ attribute :premiere_ru, Types::String
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KinopoiskUnofficialApi
4
+ module Types
5
+ class RelatedFilmResponse < Base
6
+ class Item < Base
7
+ attribute? :film_id, Types::Integer
8
+ attribute? :name_ru, Types::String.optional
9
+ attribute? :name_en, Types::String.optional
10
+ attribute? :name_original, Types::String.optional
11
+ attribute? :poster_url, Types::String
12
+ attribute? :poster_url_preview, Types::String
13
+ attribute? :relation_type, Types::String
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KinopoiskUnofficialApi
4
+ module Types
5
+ class RelatedFilmResponse < Base
6
+ attribute :total, Types::Integer
7
+ attribute :items, Types::Array.of(RelatedFilmResponse::Item)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KinopoiskUnofficialApi
4
+ module Types
5
+ class ReviewResponse < Base
6
+ class Item < Base
7
+ attribute? :kinopoisk_id, Types::Integer
8
+ attribute? :type, Types::String
9
+ attribute? :date, Types::String
10
+ attribute? :positive_rating, Types::Integer
11
+ attribute? :negative_rating, Types::Integer
12
+ attribute? :author, Types::String
13
+ attribute? :title, Types::String.optional
14
+ attribute? :description, Types::String
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KinopoiskUnofficialApi
4
+ module Types
5
+ class ReviewResponse < Base
6
+ attribute :total, Types::Integer
7
+ attribute :total_pages, Types::Integer
8
+ attribute :total_positive_reviews, Types::Integer
9
+ attribute :total_negative_reviews, Types::Integer
10
+ attribute :total_neutral_reviews, Types::Integer
11
+ attribute :items, Types::Array.of(ReviewResponse::Item)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KinopoiskUnofficialApi
4
+ module Types
5
+ class Season < Base
6
+ attribute :number, Types::Integer
7
+ attribute :episodes, Types::Array.of(Episode)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KinopoiskUnofficialApi
4
+ module Types
5
+ class SeasonResponse < Base
6
+ attribute :total, Types::Integer
7
+ attribute :items, Types::Array.of(Season)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KinopoiskUnofficialApi
4
+ module Types
5
+ class StaffResponse < Base
6
+ attribute :staff_id, Types::Integer
7
+ attribute :name_ru, Types::String.optional
8
+ attribute :name_en, Types::String.optional
9
+ attribute :description, Types::String.optional
10
+ attribute :poster_url, Types::String
11
+ attribute :profession_text, Types::String
12
+ attribute :profession_key, Types::String
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KinopoiskUnofficialApi
4
+ module Types
5
+ class VideoResponse < Base
6
+ class Item < Base
7
+ attribute? :url, Types::String
8
+ attribute? :name, Types::String
9
+ attribute? :site, Types::String
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KinopoiskUnofficialApi
4
+ module Types
5
+ class VideoResponse < Base
6
+ attribute :total, Types::Integer
7
+ attribute :items, Types::Array.of(VideoResponse::Item)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KinopoiskUnofficialApi
4
+ module Types
5
+ include Dry.Types()
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KinopoiskUnofficialApi
4
+ VERSION = "1.0.0.1"
5
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "faraday"
5
+ require "zeitwerk"
6
+ require "dry-struct"
7
+ require_relative "kinopoisk_unofficial_api/version"
8
+
9
+ loader = Zeitwerk::Loader.for_gem(warn_on_extra_files: false)
10
+ loader.inflector.inflect("endpoints" => "ENDPOINTS")
11
+ loader.setup
12
+
13
+ module KinopoiskUnofficialApi
14
+ class << self
15
+ attr_writer :configuration
16
+ end
17
+
18
+ def self.configuration
19
+ @configuration ||= Configuration.new
20
+ end
21
+
22
+ def self.configure
23
+ yield(configuration)
24
+ end
25
+ end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openapi3_parser"
4
+
5
+ INCONSISTENT_TYPES = {
6
+ "year" => %w[FilmCollectionResponse::Item KinopoiskUserVoteResponse::Item].freeze,
7
+ "growth" => %w[PersonResponse].freeze
8
+ }.freeze
9
+
10
+ # rubocop:disable Metrics/BlockLength
11
+ desc "Parse types from public json, should be up to date https://kinopoiskapiunofficial.tech/documentation/api/"
12
+ task :parse_schema do
13
+ document = Openapi3Parser.load_url("https://kinopoiskapiunofficial.tech/documentation/api/openapi.json")
14
+
15
+ result = document.components.schemas.to_h do |type_name, schema|
16
+ type_name = cast_underscored_type(type_name)
17
+
18
+ type_schema = schema.properties.to_h do |property_name, property_schema|
19
+ attribute = { type: parse_initial_type(property_schema, property_name) }
20
+
21
+ unless property_schema.any_of.nil?
22
+ attribute[:type] = property_schema.any_of.map { |item| property_schema.name || item.name || item.type }.uniq
23
+ end
24
+
25
+ attribute[:type] = attribute[:type].join if attribute[:type]&.length == 1
26
+
27
+ attribute[:nullable] = property_schema.nullable?
28
+
29
+ attribute[:required] = true if required_keys(schema).include?(property_name)
30
+
31
+ # getting required values from the description, no values in json 😔
32
+ required_value = property_schema.description&.match(/always “(.+)”|must be \*(.+)\*/)
33
+ attribute[:required_value] = (required_value[1] || required_value[2]).delete("\\") if required_value
34
+
35
+ # for some reason every property's minLength is 0 by default, probably parser bug, had to ignore that
36
+ attribute[:min_size] = property_schema[:minLength] if property_schema[:minLength] != 0
37
+ attribute[:max_size] = property_schema[:maxLength] if property_schema[:maxLength]
38
+
39
+ attribute[:items] = property_schema.items.type if property_schema&.items
40
+ if property_schema&.type == "array" && property_schema&.items&.type.nil?
41
+ attribute[:items] = property_schema&.items&.name
42
+ end
43
+
44
+ attribute[:items] = property_schema.items.name if property_schema&.items&.type == "object"
45
+
46
+ attribute[:items] = cast_underscored_type(attribute[:items]) if attribute[:items]
47
+
48
+ # hacks to fix documentation bugs
49
+ attribute[:nullable] = true if type_name == "Distribution" && property_name == "country"
50
+ attribute[:type] = "integer" if INCONSISTENT_TYPES["year"].include?(type_name) && property_name == "year"
51
+ attribute[:type] = "integer" if INCONSISTENT_TYPES["growth"].include?(type_name) && property_name == "growth"
52
+
53
+ attribute = apply_default_schema(attribute, property_schema)
54
+
55
+ underscored_property_name = property_name.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase
56
+ [underscored_property_name, attribute]
57
+ end
58
+
59
+ # find empty classes
60
+ type_schema[:type] = schema.any_of.map(&:name) if schema.properties.empty? && schema.any_of
61
+ [type_name, type_schema]
62
+ end
63
+
64
+ File.write "#{__dir__}/../data/type_attributes.json", JSON.pretty_generate(result.except("ApiError"))
65
+ end
66
+ # rubocop:enable Metrics/BlockLength
67
+
68
+ def required_keys(schema)
69
+ schema.required.to_a || []
70
+ end
71
+
72
+ def apply_default_schema(attribute, property_schema)
73
+ attribute[:default] = property_schema.default unless property_schema.default.nil?
74
+ # previous line would have been enough, but had to check the description due to issue: https://github.com/kevindew/openapi3_parser/issues/28
75
+ attribute[:default] = false if property_schema.description&.include?("Defaults to *false*")
76
+ attribute
77
+ end
78
+
79
+ def parse_initial_type(property_schema, property_name)
80
+ initial_type =
81
+ case property_schema.type
82
+ when nil then property_name.capitalize.gsub(/_(\w)/) { Regexp.last_match(1).upcase }
83
+ when "object" then property_schema.name
84
+ else property_schema.type
85
+ end
86
+
87
+ cast_underscored_type(initial_type)
88
+ end
89
+
90
+ def cast_underscored_type(type_name)
91
+ return type_name unless type_name.include?("_")
92
+
93
+ parts = type_name.split("_")
94
+ parts[1] =
95
+ case parts[1]
96
+ when "countries" then "Country"
97
+ when /s$/ then parts[1][0..-2].capitalize
98
+ when /([a-z\d])([A-Z])/ then parts[1].gsub(/([a-z\d])([A-Z])/, '\1_\2').split("_").map(&:capitalize).join
99
+ else parts[1]
100
+ end
101
+
102
+ parts.join("::")
103
+ end
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "erb"
5
+ DRY_TYPES = %w[string integer float decimal array hash symbol boolean date date_time time range].freeze
6
+
7
+ # rubocop:disable Metrics/BlockLength
8
+ desc "Rebuild types"
9
+ task :rebuild_types do
10
+ types = JSON.parse(File.read("#{__dir__}/../data/type_attributes.json"), symbolize_names: true)
11
+
12
+ types.each_pair do |name, attributes|
13
+ next build_empty_type(name, attributes) if attributes[:type].instance_of?(Array)
14
+
15
+ attributes.each_pair do |attr_name, properties|
16
+ attributes[attr_name][:type] = add_module_types(properties[:type]) unless properties[:type].is_a?(Array)
17
+ if properties[:type].is_a?(Array)
18
+ attributes[attr_name][:type] = properties[:type].map do |type|
19
+ add_module_types(type)
20
+ end.join(" | ")
21
+ end
22
+
23
+ if properties[:items].instance_of?(String)
24
+ attributes[attr_name][:type] += ".of(#{add_module_types(properties[:items])})"
25
+ elsif properties[:items] && properties[:items][:type] == "array"
26
+ attributes[attr_name][:type] += ".of(Types::Array.of(#{properties[:items][:items]}))"
27
+ end
28
+ original_type = properties[:type]
29
+
30
+ attributes = apply_required(attributes, attr_name, properties, original_type)
31
+ attributes = apply_min_max(attributes, attr_name, properties)
32
+ attributes = apply_default(attributes, attr_name, properties, original_type)
33
+
34
+ attributes[attr_name][:type] = "Types::True" if attributes[attr_name][:type] == "Types::Boolean.default(true)"
35
+ attributes[attr_name][:type] = attributes[attr_name][:type].gsub("Types::Boolean", "Types::Bool")
36
+ attributes[attr_name][:type] += ".optional" if properties[:nullable]
37
+ end
38
+
39
+ next build_nested_type(name, attributes) if name.to_s.include?("::")
40
+
41
+ File.write "#{__dir__}/../lib/kinopoisk_unofficial_api/types/#{underscore(name)}.rb",
42
+ ERB.new(File.read("#{__dir__}/templates/type.erb")).result(binding).gsub(/^\s+\n/, "")
43
+ end
44
+ end
45
+ # rubocop:enable Metrics/BlockLength
46
+
47
+ def build_empty_type(name, attributes)
48
+ attributes = attributes[:type].join(" |\n ")
49
+ File.write "#{__dir__}/../lib/kinopoisk_unofficial_api/types/#{underscore(name)}.rb",
50
+ ERB.new(File.read("#{__dir__}/templates/empty_type.erb")).result(binding).gsub(/^\s+\n/, "")
51
+ end
52
+
53
+ def build_nested_type(name, attributes)
54
+ namespace_name, type_name = name.to_s.split("::")
55
+
56
+ dir_path = "#{__dir__}/../lib/kinopoisk_unofficial_api/types/#{underscore(namespace_name)}"
57
+ FileUtils.mkdir_p(dir_path)
58
+
59
+ File.write "#{__dir__}/../lib/kinopoisk_unofficial_api/types/#{underscore(name)}.rb",
60
+ ERB.new(File.read("#{__dir__}/templates/nested_type.erb")).result(binding).gsub(/^\s+\n/, "")
61
+ end
62
+
63
+ def apply_default(attributes, attr_name, properties, original_type)
64
+ return attributes if properties[:default].nil?
65
+
66
+ attributes[attr_name][:type] += ".default(#{typecast(original_type,
67
+ properties[:default])})"
68
+ attributes
69
+ end
70
+
71
+ def apply_required(attributes, attr_name, properties, original_type)
72
+ return attributes unless properties[:required_value]
73
+
74
+ attributes[attr_name][:type] += ".constrained(eql: #{typecast(original_type,
75
+ properties[:required_value])})"
76
+ attributes
77
+ end
78
+
79
+ def apply_min_max(attributes, attr_name, properties)
80
+ return attributes unless properties[:min_size] || properties[:max_size]
81
+
82
+ constrain = ".constrained(minmax)"
83
+ constrain = properties[:min_size] ? constrain.gsub("min", "min_size: #{properties[:min_size]}, ") : ""
84
+ constrain = constrain.gsub("max", "max_size: #{properties[:max_size]}") if properties[:max_size]
85
+ attributes[attr_name][:type] += constrain
86
+ attributes
87
+ end
88
+
89
+ def add_module_types(type)
90
+ return "Types::Float | Types::Integer" if type == "number"
91
+
92
+ DRY_TYPES.include?(type) ? "Types::#{type.capitalize}" : type
93
+ end
94
+
95
+ def underscore(camel_cased_word)
96
+ camel_cased_word.to_s.gsub("::", "/")
97
+ .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
98
+ .gsub(/([a-z\d])([A-Z])/, '\1_\2')
99
+ .tr("-", "_")
100
+ .downcase
101
+ end
102
+
103
+ def typecast(type, obj)
104
+ type == "Types::String" ? "'#{obj}'" : obj
105
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KinopoiskUnofficialApi
4
+ module Types
5
+ ## Just for classes consistency
6
+ # rubocop:disable Naming/ConstantName
7
+ <%= name %> = (
8
+ <%= attributes %>
9
+ )
10
+ # rubocop:enable Naming/ConstantName
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KinopoiskUnofficialApi
4
+ module Types
5
+ class <%= namespace_name %> < Base
6
+ class <%= type_name %> < Base
7
+ <% attributes.each_pair do |name, properties| %>
8
+ <%= "#{properties[:required] ? 'attribute' : 'attribute?'} :#{name}, #{properties[:type]}" %>
9
+ <% end %>
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KinopoiskUnofficialApi
4
+ module Types
5
+ class <%= name %> < Base
6
+ <% attributes.each_pair do |name, properties| %>
7
+ <%= "#{properties[:required] ? 'attribute' : 'attribute?'} :#{name}, #{properties[:type]}" %>
8
+ <% end %>
9
+ end
10
+ end
11
+ end