162 lines · 3.6 KB · Ruby
RawDownload
module Docs  class Doc    INDEX_FILENAME = 'index.json'    DB_FILENAME = 'db.json'    META_FILENAME = 'meta.json'     class << self      include Instrumentable       attr_accessor :name, :slug, :type, :release, :abstract, :links       def inherited(subclass)        subclass.type = type      end       def version(version = nil, &block)        return @version unless block_given?         klass = Class.new(self)        klass.name = name        klass.slug = slug        klass.version = version        klass.release = release        klass.links = links        klass.class_exec(&block)        @versions ||= []        @versions << klass        klass      end       def version=(value)        @version = value.to_s      end       def versions        @versions.presence || [self]      end       def version?        version.present?      end       def versioned?        @versions.presence      end       def name        @name || super.demodulize      end       def slug        slug = @slug || default_slug || raise('slug is required')        version? ? "#{slug}~#{version_slug}" : slug      end       def version_slug        return if version.blank?        slug = version.downcase        slug.gsub! '+', 'p'        slug.gsub! '#', 's'        slug.gsub! %r{[^a-z0-9\_\.]}, '_'        slug      end       def path        slug      end       def index_path        File.join path, INDEX_FILENAME      end       def db_path        File.join path, DB_FILENAME      end       def meta_path        File.join path, META_FILENAME      end       def as_json        json = { name: name, slug: slug, type: type }        json[:links] = links if links.present?        json[:version] = version if version.present? || defined?(@version)        json[:release] = release if release.present?        json      end       def store_page(store, id)        store.open(path) do          if page = new.build_page(id) and store_page?(page)            store.write page[:store_path], page[:output]            true          else            false          end        end      end       def store_pages(store)        index = EntryIndex.new        pages = PageDb.new         store.replace(path) do          new.build_pages do |page|            next unless store_page?(page)            store.write page[:store_path], page[:output]            index.add page[:entries]            pages.add page[:path], page[:output]          end           if index.present?            store_index(store, INDEX_FILENAME, index)            store_index(store, DB_FILENAME, pages)            store_meta(store)            true          else            false          end        end      end       private       def default_slug        return if name =~ /[^A-Za-z0-9_]/        name.downcase      end       def store_page?(page)        page[:entries].present?      end       def store_index(store, filename, index)        old_json = store.read(filename) || '{}'        new_json = index.to_json        instrument "#{filename.remove('.json')}.doc", before: old_json, after: new_json        store.write(filename, new_json)      end       def store_meta(store)        json = as_json        json[:mtime] = Time.now.to_i        json[:db_size] = store.size(DB_FILENAME)        store.write(META_FILENAME, json.to_json)      end    end      def initialize      raise NotImplementedError, "#{self.class} is an abstract class and cannot be instantiated." if self.class.abstract    end     def build_page(id, &block)      raise NotImplementedError    end     def build_pages(&block)      raise NotImplementedError    end  endend