boba 0.0.8 → 0.0.9

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: c574e47f38c05d56093ec30f3f1328e28440c4ad2511567e0015106798569e44
4
- data.tar.gz: cdeb013e429306a83dd5a41023fb73c311180d88e89923cccba55eff5a613dda
3
+ metadata.gz: f7db0fba3021c2e619b8ba2a5e8d7a19173a4b66fc63f16f72ca6e3bc140ed5b
4
+ data.tar.gz: c655306579accf7b2d76bdd5e4643a16926dddb2d1bf9cf48a1a065134f11c6b
5
5
  SHA512:
6
- metadata.gz: 93de6c75462a9824d8cacd0fc0fec7ae246694eb0c63acf216cc0f04f3eb4fee94e9b98a77b6e65879eb8c11d41bf47fc06dae535b4767ecbab15150cc0c43ec
7
- data.tar.gz: 2de09551f27c892aa5317aa133f30e67b70dfa9bfbc16e7c4474e089909ba7d3bf7d1178109f94f48b09a17d774425b3d51e1eb778629b2834135d1a66daad61
6
+ metadata.gz: 6f24939c06e8e727a21c0c30d9d881493ef7de1acb88fe292384c457c73df059ae68a24c3a3a615873da40ea4d646e0fd9cb62379dc6c026ca553b47a6655ff3
7
+ data.tar.gz: 3c0f1b1931937e93a274513e47954d67605203edc9fceee6552a1aac8121af7a71bc7469e11be1a63c222fe81ba1e6b3759d415d1cc0a49bf881fb009518c24c
data/lib/boba/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Boba
5
- VERSION = "0.0.8"
5
+ VERSION = "0.0.9"
6
6
  end
@@ -0,0 +1,132 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+ return if !defined?(AttrJson::Record)
5
+
6
+ module Tapioca
7
+ module Dsl
8
+ module Compilers
9
+ # `Tapioca::Dsl::Compilers::AttrJson` decorates RBI files for classes that use the `AttrJson` gem.
10
+ # https://github.com/jrochkind/attr_json
11
+ #
12
+ # For example, with the following ActiveRecord model:
13
+ # ~~~rb
14
+ # class Product < ActiveRecord::Base
15
+ # include AttrJson::Record
16
+ #
17
+ # attr_json :price_cents, :integer
18
+ # end
19
+ # ~~~
20
+ #
21
+ # This compiler will generate the following RBI:
22
+ # ~~~rbi
23
+ # class Product
24
+ # include AttrJsonGeneratedMethods
25
+ # extend AttrJson::Record::ClassMethods
26
+ #
27
+ # module AttrJsonGeneratedMethods
28
+ # sig { returns(::Integer) }
29
+ # def price_cents; end
30
+ #
31
+ # sig { params(value: Integer).returns(::Integer) }
32
+ # def price_cents=(value); end
33
+ # end
34
+ # end
35
+ # ~~~
36
+ class AttrJson < Tapioca::Dsl::Compiler
37
+ extend T::Sig
38
+
39
+ # Class methods module is already defined in the gem rbi, so just reference it here.
40
+ ClassMethodsModuleName = "AttrJson::Record::ClassMethods"
41
+ InstanceMethodModuleName = "AttrJsonGeneratedMethods"
42
+ ConstantType = type_member {{ fixed: T.any(T.class_of(::AttrJson::Record), T.class_of(::AttrJson::Model)) }}
43
+
44
+ class << self
45
+ extend T::Sig
46
+
47
+ sig { override.returns(T::Enumerable[Module]) }
48
+ def gather_constants
49
+ all_classes.select { |constant| constant < ::AttrJson::Record || constant < ::AttrJson::Model }
50
+ end
51
+ end
52
+
53
+ sig { override.void }
54
+ def decorate
55
+ rbi_class = root.create_path(constant)
56
+ instance_module = RBI::Module.new(InstanceMethodModuleName)
57
+
58
+ decorate_attributes(instance_module)
59
+
60
+ rbi_class << instance_module
61
+ rbi_class.create_include(InstanceMethodModuleName)
62
+ rbi_class.create_extend(ClassMethodsModuleName) if constant < ::AttrJson::Record
63
+ end
64
+
65
+ private
66
+
67
+ def decorate_attributes(rbi_scope)
68
+ T.unsafe(constant).attr_json_registry
69
+ .definitions
70
+ .sort_by(&:name) # this is annoying, but we need to sort to force consistent ordering or the rbi checks fail
71
+ .each do |definition|
72
+ _, type, options = definition.original_args
73
+ attribute_name = definition.name
74
+ type_name = sorbet_type(type, array: !!options[:array], nilable: !!options[:nil])
75
+
76
+ # Model: attr_json(:other_model_id, :string)
77
+ # => other_model_id
78
+ # => other_model_id=
79
+ rbi_scope.create_method(attribute_name, return_type: type_name)
80
+ rbi_scope.create_method(
81
+ "#{attribute_name}=",
82
+ parameters: [create_param("value", type: type_name)],
83
+ return_type: type_name,
84
+ )
85
+ end
86
+ end
87
+
88
+ def symbol_type(type_name)
89
+ return type_name if type_name.is_a?(Symbol)
90
+ return type_name.to_sym if type_name.is_a?(String)
91
+
92
+ type_name.type
93
+ end
94
+
95
+ def sorbet_type(type_name, array: false, nilable: false)
96
+ sorbet_type = if type_name.respond_to?(:model)
97
+ type_name.model
98
+ else
99
+ case symbol_type(type_name)
100
+ when :string, :immutable_string, :text, :uuid, :binary
101
+ "String"
102
+ when :boolean
103
+ "T::Boolean"
104
+ when :integer, :big_integer
105
+ "Integer"
106
+ when :float
107
+ "Float"
108
+ when :decimal
109
+ "BigDecimal"
110
+ when :time, :datetime
111
+ "Time"
112
+ when :date
113
+ "Date"
114
+ when :money
115
+ "Money"
116
+ when :json
117
+ "T.untyped"
118
+ else
119
+ "T.untyped"
120
+ end
121
+ end
122
+
123
+ sorbet_type = "::#{sorbet_type}"
124
+ sorbet_type = "T::Array[#{sorbet_type}]" if array
125
+ sorbet_type = "T.nilable(#{sorbet_type})" if nilable # todo: improve this
126
+
127
+ sorbet_type
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,77 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ return unless defined?(Paperclip)
5
+
6
+ module Tapioca
7
+ module Dsl
8
+ module Compilers
9
+ # `Tapioca::Dsl::Compilers::Paperclip` decorates RBI files for classes that use the `has_attached_file` method
10
+ # provided by the `paperclip` gem.
11
+ # https://github.com/thoughtbot/paperclip
12
+ #
13
+ # For example, with the following ActiveRecord model:
14
+ # ~~~rb
15
+ # class Product < ActiveRecord::Base
16
+ # has_attached_file(:marketing_image)
17
+ # end
18
+ # ~~~
19
+ #
20
+ # This compiler will generate the following RBI:
21
+ # ~~~rbi
22
+ # class Product
23
+ # include PaperclipGeneratedMethods
24
+ #
25
+ # module PaperclipGeneratedMethods
26
+ # sig { returns(::Paperclip::Attachment) }
27
+ # def marketing_image; end
28
+ #
29
+ # sig { params(value: T.untyped).void }
30
+ # def marketing_image=(value); end
31
+ # end
32
+ # end
33
+ # ~~~
34
+ class Paperclip < Tapioca::Dsl::Compiler
35
+ extend T::Sig
36
+ include RBIHelper
37
+
38
+ InstanceModuleName = "PaperclipGeneratedMethods"
39
+ ConstantType = type_member { { fixed: T.class_of(::Paperclip::Glue) } }
40
+
41
+ class << self
42
+ extend T::Sig
43
+
44
+ sig { override.returns(T::Enumerable[Module]) }
45
+ def gather_constants
46
+ all_classes.select { |c| c < ::Paperclip::Glue }
47
+ end
48
+ end
49
+
50
+ sig { override.void }
51
+ def decorate
52
+ attachments = ::Paperclip::AttachmentRegistry.names_for(constant)
53
+ return if attachments.empty?
54
+
55
+ root.create_path(constant) do |klass|
56
+ instance_module = RBI::Module.new(InstanceModuleName)
57
+
58
+ attachments.each do |attachment_name|
59
+ # Model: has_attached_file(:marketing_image)
60
+ # => marketing_image
61
+ # => marketing_image=
62
+ instance_module.create_method(attachment_name, return_type: "::Paperclip::Attachment")
63
+ instance_module.create_method(
64
+ "#{attachment_name}=",
65
+ parameters: [create_param("value", type: "T.untyped")],
66
+ return_type: nil,
67
+ )
68
+ end
69
+
70
+ klass << instance_module
71
+ klass.create_include(InstanceModuleName)
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -21,6 +21,11 @@ module Tapioca
21
21
  def decorate
22
22
  return if constant.state_machines.empty?
23
23
 
24
+ # This is a hack to make sure the instance methods are defined on the constant. Somehow the constant is being
25
+ # loaded but the actual `state_machine` call is not being executed, so the instance methods don't exist yet.
26
+ # Instantiating an empty class fixes it.
27
+ constant.try(:new)
28
+
24
29
  super()
25
30
 
26
31
  root.create_path(T.unsafe(constant)) do |klass|
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: boba
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.8
4
+ version: 0.0.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Angellist
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-10-27 00:00:00.000000000 Z
11
+ date: 2024-11-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sorbet-static-and-runtime
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 0.16.2
33
+ version: 0.16.4
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 0.16.2
40
+ version: 0.16.4
41
41
  description:
42
42
  email:
43
43
  - alex.stathis@angellist.com
@@ -54,16 +54,18 @@ files:
54
54
  - lib/boba/version.rb
55
55
  - lib/tapioca/dsl/compilers/active_record_associations_persisted.rb
56
56
  - lib/tapioca/dsl/compilers/active_record_columns_persisted.rb
57
+ - lib/tapioca/dsl/compilers/attr_json.rb
57
58
  - lib/tapioca/dsl/compilers/money_rails.rb
59
+ - lib/tapioca/dsl/compilers/paperclip.rb
58
60
  - lib/tapioca/dsl/compilers/state_machines_extended.rb
59
61
  homepage: https://github.com/angellist/boba
60
62
  licenses:
61
63
  - MIT
62
64
  metadata:
63
65
  bug_tracker_uri: https://github.com/angellist/boba/issues
64
- changelog_uri: https://github.com/angellist/boba/blob/0.0.8/History.md
66
+ changelog_uri: https://github.com/angellist/boba/blob/0.0.9/History.md
65
67
  homepage_uri: https://github.com/angellist/boba
66
- source_code_uri: https://github.com/angellist/boba/tree/0.0.8
68
+ source_code_uri: https://github.com/angellist/boba/tree/0.0.9
67
69
  rubygems_mfa_required: 'true'
68
70
  post_install_message:
69
71
  rdoc_options: []
@@ -80,7 +82,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
80
82
  - !ruby/object:Gem::Version
81
83
  version: '0'
82
84
  requirements: []
83
- rubygems_version: 3.5.16
85
+ rubygems_version: 3.5.22
84
86
  signing_key:
85
87
  specification_version: 4
86
88
  summary: Custom Tapioca compilers