lib/jsus/source_file.rb in jsus-0.1.4 vs lib/jsus/source_file.rb in jsus-0.1.5

- old
+ new

@@ -1,20 +1,41 @@ +# +# SourceFile is a base for any Jsus operation. +# +# It contains basic info about source as well as file content. +# +# module Jsus class SourceFile - attr_accessor :relative_filename - attr_accessor :filename - attr_accessor :content - attr_accessor :package - # constructors + attr_accessor :relative_filename, :filename, :package # :nodoc: + # Constructors + # Basic constructor. + # + # You probably should use SourceFile.from_file instead. + # + # But if you know what you are doing, it accepts the following values: + # * +package+ — an instance of Package, normally passed by a parent + # * +relative_filename+ — used in Package, for generating tree structure of the source files + # * +filename+ — full filename for the given package + # * +content+ — file content of the source file + # * +pool+ — an instance of Pool def initialize(options = {}) - [:header, :relative_filename, :filename, :content, :package].each do |field| + [:package, :header, :relative_filename, :filename, :content, :pool].each do |field| send("#{field}=", options[field]) if options[field] end - options[:pool] << self if options[:pool] end + # + # Initializes a SourceFile given the filename and options + # + # options: + # * <tt>:pool:</tt> — an instance of Pool + # * <tt>:package:</tt> — an instance of Package + # + # returns either an instance of SourceFile or nil when it's not possible to parse the input + # def self.from_file(filename, options = {}) if File.exists?(filename) source = File.read(filename) yaml_data = source.match(%r(^/\*\s*(---.*?)\*/)m) if (yaml_data && yaml_data[1] && header = YAML.load(yaml_data[1])) @@ -22,72 +43,185 @@ options[:relative_filename] = filename options[:filename] = File.expand_path(filename) options[:content] = source new(options) else - #puts "WARNING: file #{filename} has invalid format (should be YAML)" +# puts "WARNING: file #{filename} has invalid format (should be YAML)" nil end else - #puts "WARNING: file #{filename} does not exist" +# puts "WARNING: file #{filename} does not exist" nil end end # Public API - def header=(new_header) - @header = new_header - # prepare defaults - @header["description"] ||= "" - @header["requires"] = [@header["requires"] || []].flatten - @header["requires"].map! {|r| r.gsub(/^(\.)?\//, "") } - @header["provides"] = [@header["provides"] || []].flatten - end + # + # Returns a header parsed from YAML-formatted source file first comment. + # Contains information about authorship, naming, source files, etc. + # def header self.header = {} unless @header @header end - def dependencies(options = {}) - if !options[:short] && package - header["requires"].map {|r| r.index("/") ? r : "#{package.name}/#{r}"} - else - header["requires"] - end + # + # A string containing the description of the source file. + # + def description + header["description"] end + + # + # Returns an array of dependencies tags. Unordered. + # + def dependencies + @dependencies + end alias_method :requires, :dependencies + # + # Returns an array with names of dependencies. Unordered. + # Accepts options: + # * <tt>:short:</tt> — whether inner dependencies should not prepend package name + # e.g. 'Class' instead of 'Core/Class' when in package 'Core'). + # Doesn't change anything for external dependencies + # + def dependencies_names(options = {}) + dependencies.map {|d| d.name(options) } + end + alias_method :requires_names, :dependencies_names + + # + # Returns an array of external dependencies tags. Unordered. + # def external_dependencies - dependencies(:short => true).select {|d| d.index("/") } + dependencies.select {|d| d.external? } end - def internal_dependencies - dependencies(:short => true) - external_dependencies + # + # Returns an array with names for external dependencies. Unordered. + # + def external_dependencies_names + external_dependencies.map {|d| d.name } end - def provides(options = {}) - if !options[:short] && package - header["provides"].map {|p| "#{package.name}/#{p}"} - else - header["provides"] + # + # Returns an array with provides tags. + # + def provides + @provides + end + + # + # Returns an array with provides names. + # Accepts options: + # * <tt>:short:</tt> — whether provides should not prepend package name + # e.g. 'Class' instead of 'Core/Class' when in package 'Core') + def provides_names(options = {}) + provides.map {|p| p.name(options)} + end + + + # + # Returns a tag for source file, which this one is an extension for. + # + # E.g.: file Foo.js in package Core provides ['Class', 'Hash']. File Bar.js in package Bar + # extends 'Core/Class'. That means its contents would be appended to the Foo.js when compiling + # the result. + # + def extends + @extends + end + + # + # Returns whether the source file is an extension. + # + def extension? + extends && !extends.empty? + end + + # + # Returns an array of included extensions for given source. + # + def extensions + @extensions ||= [] + @extensions = @extensions.flatten.compact.uniq + @extensions + end + + def extensions=(new_value) # :nodoc: + @extensions = new_value + end + + # + # Looks up for extensions in the #pool and then includes + # extensions for all the provides tag this source file has. + # + def include_extensions! + if pool + provides.each do |p| + extensions << pool.lookup_extensions(p) + end end end - def description - header["description"] + # + # Returns an array of files required by this files including all the filenames for extensions. + # SourceFile filename always goes first, all the extensions are unordered. + # + def required_files + [filename, extensions.map {|e| e.filename}].flatten end + # + # Returns a hash containing basic info with dependencies/provides tags' names + # and description for source file. + # def to_hash { "desc" => description, - "requires" => dependencies(:short => true), - "provides" => provides(:short => true) + "requires" => dependencies_names(:short => true), + "provides" => provides_names(:short => true) } end - def inspect + def inspect # :nodoc: self.to_hash.inspect end + # Private API + + def header=(new_header) # :nodoc: + @header = new_header + # prepare defaults + @header["description"] ||= "" + # handle tags + @dependencies = [@header["requires"] || []].flatten + @dependencies.map! {|tag_name| Tag.new(tag_name, :package => package) } + @provides = [@header["provides"] || []].flatten + @provides.map! {|tag_name| Tag.new(tag_name, :package => package) } + @extends = (@header["extends"] && !@header["extends"].empty?) ? Tag.new(@header["extends"]) : nil + end + def content=(new_value) # :nodoc: + @content = new_value + end + + def content # :nodoc: + [@content, extensions.map {|e| e.content}].flatten.compact.join("\n") + end + + # Assigns an instance of Jsus::Pool to the source file. + # Also performs push to that pool. + def pool=(new_value) + @pool = new_value + @pool << self if @pool + end + + # A pool which the source file is assigned to. Used in #include_extensions! + def pool + @pool + end + end end \ No newline at end of file