templates/api/fulldoc/html/setup.rb in yard-api-0.2.3 vs templates/api/fulldoc/html/setup.rb in yard-api-0.3.0

- old
+ new

@@ -1,29 +1,77 @@ require 'pathname' +require 'json' include YARD::Templates::Helpers::ModuleHelper include YARD::Templates::Helpers::FilterHelper def init + YARD::APIPlugin.logger.info "YARD-API: starting." + + options.serializer = YARD::APIPlugin::Serializer.new + options.serializer.basepath = api_options.output + + options.objects.each do |object| + object[:api_id] = object.tag('API').text.lines.first + end + options[:resources] = options[:objects]. - group_by { |o| o.tags('API').first.text.split("\n").first }. + group_by { |o| o[:api_id] }. sort_by { |o| o.first } build_json_objects_map generate_assets if api_options.one_file return serialize_onefile_index end - serialize_index if File.exists?(api_options['readme']) + serialize_index if File.exists?(api_options['readme'] || '') serialize_static_pages serialize_resource_index if api_options['resource_index'] options.delete(:objects) options[:resources].each do |resource, controllers| + controllers.each do |controller| + if controller.is_a?(YARD::CodeObjects::NamespaceObject) + co = YARD::CodeObjects::ClassObject.new( + YARD::APIPlugin::Registry.root, + controller[:api_id] + ) + + YARD::Registry.register co + + (controller.tags(:object) + controller.tags(:model)).each do |tag| + tag_co = YARD::CodeObjects::APIObject.new(co, tag.text.lines[0].strip) + tag_co.object = tag.object + + # Make an alias on the global API namespace, for convenience. + # Now an object called "Bar" under the "Foo" controller can be + # referenced using [API::Bar] as well as [API::Foo::Bar] which will + # never face any conflicts. + shortcut_tag_co = YARD::CodeObjects::APIObject.new(YARD::APIPlugin::Registry.root, tag.text.lines[0].strip) + shortcut_tag_co.object = tag.object + + # We need to override #namespace because #url_for() uses it to + # generate the url, which has to be done usign #object and not + # #namespace (which points to P("API") and we want + # P("API::#{tag.object.path}")). + shortcut_tag_co.namespace = tag.object + + YARD::Registry.register(tag_co) + YARD::Registry.register(shortcut_tag_co) + end + end + end + + # debugger + + if controllers.length > 1 + debugger + end + serialize_resource(resource, controllers) end end def serialize(object) @@ -32,16 +80,25 @@ T('layout').run(options) end end def serialize_resource(resource, controllers) + YARD::APIPlugin.logger.info('=' * 80) + YARD::APIPlugin.logger.info ">>> #{resource} <<< (#{controllers})" + YARD::APIPlugin.logger.info('-' * 80) + options[:object] = resource options[:controllers] = controllers - Templates::Engine.with_serializer("#{topicize resource}.html", options[:serializer]) do - T('layout').run(options) + + controllers.each do |controller| + Templates::Engine.with_serializer(controller, options.serializer) do + T('layout').run(options) + end end + options.delete(:controllers) + YARD::APIPlugin.logger.info('-' * 80) end def serialize_index options[:file] = api_options['readme'] serialize('index.html') @@ -91,14 +148,57 @@ def build_json_objects_map options[:json_objects_map] = {} options[:json_objects] = {} options[:resources].each do |r,cs| cs.each do |controller| - (controller.tags(:object) + controller.tags(:model)).each do |obj| - name, json = obj.text.split(%r{\n+}, 2).map(&:strip) - options[:json_objects_map][name] = topicize r - options[:json_objects][r] ||= [] - options[:json_objects][r] << [name, json] + (controller.tags(:object) + controller.tags(:model)).each do |tag| + name, json_string = tag.text.split(%r{\n+}, 2).map(&:strip) + + if json = parse_json(json_string) + options[:json_objects_map][name] = topicize r + options[:json_objects][r] ||= [] + options[:json_objects][r] << [name, json] + end end + end + end +end + +def parse_json(json_string) + JSON::parse(json_string || '').tap do |json| + validate_json_schema(json, ->(msg) { + raise <<-MSG + #{'=' * 32} + #{msg.strip} + #{'-' * 32} + Offending JSON belongs to: "#{name}" in "#{tag.object.path}". + #{'=' * 32} + MSG + }) + end +rescue JSON::ParserError => e + YARD::APIPlugin.on_error( + <<-MSG + #{'*' * 32} + A @#{tag.tag_name} docstring contains invalid JSON. + Offending JSON belongs to "#{name}" in "#{tag.object.path}". + --- + #{tag} + --- + #{e} + #{'*' * 32} + MSG + ) + + nil +end + +def validate_json_schema(schema, on_error) + if schema_is_model?(schema) + if !schema['description'].is_a?(String) + on_error.call <<-MSG + Expected "description" to be a String, got #{schema['description'].class}. + Value: #{schema['description'].to_json} + MSG end end end