Class: Alain::Proto

Inherits:
Object
  • Object
show all
Includes:
Util
Defined in:
lib/alain/proto.rb

Constant Summary collapse

INDENT =
' ' * 4

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Util

grpc_method, namespace, snake_case

Constructor Details

#initialize(service, package, proto_path) ⇒ Proto

Returns a new instance of Proto.



11
12
13
14
15
16
17
18
19
# File 'lib/alain/proto.rb', line 11

def initialize(service, package, proto_path)
  unless File.exist? proto_path
    STDERR.puts "#{proto_path} not found. Exit"
    exit 1
  end
  @path = proto_path
  @service = service
  @package = package
end

Instance Attribute Details

#packageObject (readonly)

Returns the value of attribute package.



8
9
10
# File 'lib/alain/proto.rb', line 8

def package
  @package
end

#serviceObject (readonly)

Returns the value of attribute service.



8
9
10
# File 'lib/alain/proto.rb', line 8

def service
  @service
end

Class Method Details

.parse(proto_path) ⇒ Object



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/alain/proto.rb', line 81

def self.parse(proto_path)
  package = nil
  service = {}
  current_svc = nil
  File.foreach(proto_path) do |line|
    case line
    when /^\s*package\s+(\S+)\s*;/
      package = $1
    when /^\s*service\s+(\S+)\s*{/
      current_svc = $1
      service[current_svc] ||= []
    when /^\s*rpc\s+(\S+)\s*\((\S+)\)\s+returns\s+\((\S+)\)\s*{/
      service[current_svc] << {
        method: $1,
        request: $2,
        response: $3
      }
    when /^\s*message\s+(\S+)\s*{/
      # Filling nested messages
      service[current_svc] << {
        request: $1,
        method: nil, response: nil
      }
    end
  end
  new(service, package, proto_path)
end

Instance Method Details

#compile_protosObject



39
40
41
42
43
# File 'lib/alain/proto.rb', line 39

def compile_protos
  <<~EOS
  tonic_build::compile_protos("#{@path}")?;
  EOS
end

#mod_defObject

Tonic import macro



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/alain/proto.rb', line 47

def mod_def
  _, other_ns = parse_import
  namespaces = [@package].concat other_ns.keys
  [].tap do |res|
    namespaces.each do |namespace|
      ns = namespace.split('.')
      res << ns.map.with_index do |n, i|
        INDENT * i + "pub mod #{n} {"
      end
      res << INDENT * ns.length + %%tonic::include_proto!("#{@package}");%
      res << ns.map.with_index do |n, i|
        INDENT * (ns.length - i - 1) + '}'
      end
    end
  end.join("\n")
end

#parse_importObject



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/alain/proto.rb', line 122

def parse_import
  package_ns = ["#{service_name(:snake)}_server::#{service_name}"]
  other_ns = {}
  @service.each do |svc, methods|
    methods.each do |method|
      [:request, :response].each do |message_type|
        next if method[message_type].nil?

        case method[message_type]
        when /^(.+)\.(\S+?)$/
          other_ns[$1] ||= []
          other_ns[$1] << $2
        else
          package_ns << method[message_type]
        end
      end
    end
  end
  [package_ns.uniq, other_ns]
end

#server_modObject



118
119
120
# File 'lib/alain/proto.rb', line 118

def server_mod
  "#{namespace}::#{service_name :snake}_server::#{service_name}Server"
end

#service_name(mode = :camel) ⇒ Object



109
110
111
112
113
114
115
116
# File 'lib/alain/proto.rb', line 109

def service_name(mode = :camel)
  case mode
  when :snake
    snake_case @service.keys.first
  else
    @service.keys.first
  end
end

#svc_methodsObject



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/alain/proto.rb', line 21

def svc_methods
  [].tap do |res|
    @service.each do |svc, methods|
      res << "pub struct #{svc}Service {}"
      res << ''
      res << '#[tonic::async_trait]'
      res << "impl #{svc} for #{svc}Service {"
      res << ''
      methods.each do |method|
        next if method[:method].nil?

        res << INDENT + grpc_method(method[:method], method[:request], method[:response])
      end
      res << "}"
    end
  end.join("\n")
end

#use_def(crate = 'crate') ⇒ Object

use definition for shorthand



66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/alain/proto.rb', line 66

def use_def(crate = 'crate')
  package_ns, other_ns = parse_import
  [].tap do |res|
    res << "use #{crate}::#{namespace}::{"
    package_ns.uniq.each { |message| res << "#{INDENT}#{message}," }
    res << '};'
    res << ''
    other_ns.each do |ns, messages|
      res << "use crate::#{ns.gsub('.', '::')}::{"
      messages.uniq.each { |message| res << "#{INDENT}#{message}," }
      res << '};'
    end
  end.join("\n")
end