Skip to content

Instantly share code, notes, and snippets.

@a-suenami
Last active July 24, 2019 03:04
Show Gist options
  • Save a-suenami/2bb5d6238dfb86f19a5f76206029d0d2 to your computer and use it in GitHub Desktop.
Save a-suenami/2bb5d6238dfb86f19a5f76206029d0d2 to your computer and use it in GitHub Desktop.
sorbet
class MyHash
def initialize(hash)
@hash = hash
## all classes
# class => name
## class
# class => name
# or module
## dependency types
# has_one => name, type (class_name)
# has_many => name, type (class_name)
# belongs_to => name, type (class_name)
# const -> type (class_name)
# joins, includes, eager_load
# include
# extend
# dependency strength (count of call)
# call -> reveiver -> type (class_name)
end
def [](key)
value = @hash[key]
if value.is_a?(Hash)
self.class.new(value)
else
value
end
end
def keys
@hash.keys
end
def has_key?(key)
@hash.has_key?(key)
end
def deep_merge(another)
all_keys = (self.keys + another.keys).uniq
merged =
all_keys.map do |key|
value =
if self.has_key?(key) && !another.has_key?(key)
self[key]
elsif !self.has_key?(key) && another.has_key?(key)
another[key]
else
if self[key].is_a?(self.class) && another[key].is_a?(self.class)
self[key].deep_merge(another[key])
elsif self[key].is_a?(Array) && another[key].is_a?(Array)
self[key] + another[key]
else
another[key]
end
end
[key, value]
end.to_h
self.class.new(merged)
end
def to_s
@hash.to_s
end
end
# class NodeParser
# def reducer(dependency_struct, node)
# end
# end
#
# class ClassNodeParser
# def reducer(struct, node)
# end
# end
#
# class VarNodeParser
# def reducer(struct, node)
#
# end
# end
# class CallNodeParser
# def reducer(struct, node)
# new_struct = MyHash.new
# args = node.children[2]
# var_parser = VarNodeParser.new
# new_struct = var_parser.reducer(new_struct, args)
# new_struct[:type] = 'call'
# new_struct[:name] = node.children[1]
# end
# end
#
# class ConstNodeParser
# end
def handle_node(node)
# https://qiita.com/siman/items/3017ed399ded43229189#call
end_conditions = {
call: -> (children) {
_receiver = children[0]
method_name = children[1]
_arguments = children[2]
MyHash.new(method_calls: [{ name: method_name }])
},
# これだとちょっと微妙
# vcall: -> (children) {
# MyHash.new(vcall: [children[0]])
# },
const: -> (children) {
MyHash.new(consts: [children[0]])
}
}
node_type_key = node.type.downcase.to_sym
if end_conditions.has_key?(node_type_key)
end_conditions[node_type_key].call(node.children)
else
node
|> children
|> select{ |child| child.is_a?(RubyVM::AbstractSyntaxTree::Node) }
|> map { |node| handle_node(node) }
|> compact
|> reduce(&:deep_merge)
end
end
foo_ast = RubyVM::AbstractSyntaxTree.parse_file('/Users/suenami/Projects/otomo-team/otomo-travel/app/models/guide.rb')
# puts foo_ast.type
# foo_ast.children.each do |e|
# puts e.inspect
# end
# parsed_ast = recursive(foo_ast)
# puts parsed_ast.inspect
puts handle_node(foo_ast).inspect
# typed: strong
require 'foo.rb'
class Bar
sig {params(value: Foo).void}
def initialize(value)
@value = T.let(value, Foo)
end
sig {returns(String)}
def to_s
@value.to_i.to_s
end
end
# typed: strong
require 'bar.rb'
class Baz
sig {params(value: String).void}
def initialize(value)
@value = T.let(value, String)
end
sig {params(arg: Bar).returns(String)}
def do_something(arg)
@value + arg.to_s
end
end
# typed: strong
class Foo
sig {params(value: Integer).void}
def initialize(value)
@value = T.let(value, Integer)
end
sig {returns(Integer)}
def to_i
@value
end
end
# frozen_string_literal: true
source "https://rubygems.org"
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
gem "sorbet"
GEM
remote: https://rubygems.org/
specs:
sorbet (0.4.4463)
sorbet-static (= 0.4.4463)
sorbet-static (0.4.4463-universal-darwin-14)
PLATFORMS
ruby
DEPENDENCIES
sorbet
BUNDLED WITH
2.1.0.pre.1
@a-suenami
Copy link
Author

[suenami:~/Projects/a-suenami/2bb5d6238dfb86f19a5f76206029d0d2] bundle exec srb tc --ignore=sorbet/ --quiet --print=ast
class <emptyTree>::<C Bar><<C <todo sym>>> < (::<todo sym>)
  <self>.sig() do ||
    <self>.params({:"value" => <emptyTree>::<C Foo>}).void()
  end

  def initialize<<C <todo sym>>>(value, &<blk>)
    @value = <emptyTree>::<C T>.let(value, <emptyTree>::<C Foo>)
  end

  <self>.sig() do ||
    <self>.returns(<emptyTree>::<C String>)
  end

  def to_s<<C <todo sym>>>(&<blk>)
    @value.to_i().to_s()
  end
end
class <emptyTree>::<C Baz><<C <todo sym>>> < (::<todo sym>)
  <self>.sig() do ||
    <self>.params({:"value" => <emptyTree>::<C String>}).void()
  end

  def initialize<<C <todo sym>>>(value, &<blk>)
    @value = <emptyTree>::<C T>.let(value, <emptyTree>::<C String>)
  end

  <self>.sig() do ||
    <self>.params({:"arg" => <emptyTree>::<C Bar>}).returns(<emptyTree>::<C String>)
  end

  def do_something<<C <todo sym>>>(arg, &<blk>)
    @value.+(arg.to_s())
  end
end
class <emptyTree>::<C Foo><<C <todo sym>>> < (::<todo sym>)
  <self>.sig() do ||
    <self>.params({:"value" => <emptyTree>::<C Integer>}).void()
  end

  def initialize<<C <todo sym>>>(value, &<blk>)
    @value = <emptyTree>::<C T>.let(value, <emptyTree>::<C Integer>)
  end

  <self>.sig() do ||
    <self>.returns(<emptyTree>::<C Integer>)
  end

  def to_i<<C <todo sym>>>(&<blk>)
    @value
  end
end
No errors! Great job.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment