generate_source.rb 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. # encoding: UTF-8
  2. require 'thor'
  3. require 'pathname'
  4. require 'active_support/core_ext/hash/deep_merge'
  5. require 'active_support/inflector'
  6. require 'multi_json'
  7. require 'coderay'
  8. require 'pry'
  9. module Elasticsearch
  10. module API
  11. # A command line application based on [Thor](https://github.com/wycats/thor),
  12. # which will read the JSON API spec file(s), and generate
  13. # the Ruby source code (one file per API endpoint) with correct
  14. # module namespace, method names, and RDoc documentation,
  15. # as well as test files for each endpoint.
  16. #
  17. # Currently it only generates Ruby source, but can easily be
  18. # extended and adapted to generate source code for other
  19. # programming languages.
  20. #
  21. class SourceGenerator < Thor
  22. namespace 'api:code'
  23. include Thor::Actions
  24. __root = Pathname( File.expand_path('../../..', __FILE__) )
  25. desc "generate <PATH TO JSON SPEC FILES>", "Generate source code and tests from the REST API JSON specification"
  26. method_option :language, default: 'ruby', desc: 'Programming language'
  27. method_option :force, type: :boolean, default: false, desc: 'Overwrite the output'
  28. method_option :verbose, type: :boolean, default: false, desc: 'Output more information'
  29. method_option :input, default: File.expand_path('../../../api-spec', __FILE__), desc: 'Path to directory with JSON API specs'
  30. method_option :output, default: File.expand_path('../../../tmp/out', __FILE__), desc: 'Path to output directory'
  31. def generate(*files)
  32. self.class.source_root File.expand_path('../', __FILE__)
  33. @input = Pathname(options[:input])
  34. @output = Pathname(options[:output])
  35. # -- Test helper
  36. copy_file "templates/ruby/test_helper.rb", @output.join('test').join('test_helper.rb') if options[:language] == 'ruby'
  37. files.each do |file|
  38. @path = Pathname(file)
  39. @json = MultiJson.load( File.read(@path) )
  40. @spec = @json.values.first
  41. say_status 'json', @path, :yellow
  42. # say_status 'JSON', @spec.inspect, options[:verbose]
  43. @full_namespace = @json.keys.first.split('.')
  44. @namespace_depth = @full_namespace.size > 0 ? @full_namespace.size-1 : 0
  45. @module_namespace = @full_namespace[0, @namespace_depth]
  46. @method_name = @full_namespace.last
  47. # -- Ruby files
  48. @path_to_file = @output.join('api').join( @module_namespace.join('/') ).join("#{@method_name}.rb")
  49. empty_directory @output.join('api').join( @module_namespace.join('/') )
  50. template "templates/#{options[:language]}/method.erb", @path_to_file
  51. if options[:verbose]
  52. colorized_output = CodeRay.scan_file(@path_to_file, :ruby).terminal
  53. lines = colorized_output.split("\n")
  54. say_status options[:language].downcase,
  55. lines.first + "\n" + lines[1, lines.size].map { |l| ' '*14 + l }.join("\n"),
  56. :yellow
  57. end
  58. # --- Test files
  59. @test_directory = @output.join('test/api').join( @module_namespace.join('/') )
  60. @test_file = @test_directory.join("#{@method_name}_test.rb")
  61. empty_directory @test_directory
  62. template "templates/#{options[:language]}/test.erb", @test_file
  63. if options[:verbose]
  64. colorized_output = colorized_output = CodeRay.scan_file(@test_file, :ruby).terminal
  65. lines = colorized_output.split("\n")
  66. say_status options[:language].downcase,
  67. lines.first + "\n" + lines[1, lines.size].map { |l| ' '*14 + l }.join("\n"),
  68. :yellow
  69. say '▬'*terminal_width
  70. end
  71. end
  72. # -- Tree output
  73. if options[:verbose] && `which tree > /dev/null 2>&1`
  74. lines = `tree #{@output}`.split("\n")
  75. say_status 'tree',
  76. lines.first + "\n" + lines[1, lines.size].map { |l| ' '*14 + l }.join("\n")
  77. end
  78. end
  79. private
  80. # Create the hierarchy of directories based on API namespaces
  81. #
  82. def __create_directories(key, value)
  83. unless value['documentation']
  84. empty_directory @output.join(key)
  85. create_directory_hierarchy *value.to_a.first
  86. end
  87. end
  88. end
  89. end
  90. end