lib/scaffoldhub/specification.rb in scaffoldhub-0.0.4 vs lib/scaffoldhub/specification.rb in scaffoldhub-0.0.6
- old
+ new
@@ -1,48 +1,174 @@
require 'yaml'
+def mattr_accessor(*syms)
+ syms.each do |sym|
+ class_eval(<<-EOS, __FILE__, __LINE__)
+ @@#{sym} = nil
+
+ def self.#{sym}
+ @@#{sym}
+ end
+
+ def self.#{sym}=(obj)
+ @@#{sym} = obj
+ end
+ EOS
+ end
+end
+
+def define_dsl_attributes(*syms)
+ syms.each do |sym|
+ class_eval(<<-EOS, __FILE__, __LINE__)
+ def #{sym}(val)
+ self.class.#{sym} = val
+ end
+ EOS
+ end
+end
+
+def define_dsl_file_keyword(*syms)
+ syms.each do |sym|
+ class_eval(<<-EOS, __FILE__, __LINE__)
+ def #{sym}(src, options = {})
+ file(src, options, :#{sym})
+ end
+ EOS
+ end
+end
+
module Scaffoldhub
class Specification
+ mattr_accessor :name, :description, :base_url, :blog_post, :screenshot, :parameter_example
+ define_dsl_attributes :name, :description, :base_url, :blog_post, :screenshot, :parameter_example
+
+ mattr_accessor :files, :errors, :tags
@@files = []
- @@base_url = nil
+ @@errors = []
+ @@tags = []
+ define_dsl_file_keyword :model, :migration, :controller, :view, :layout
+
class << self
- def files
- @@files
+
+ def add_file(src, dest, type)
+ @@files << { :type => type, :src => src, :dest => dest }
end
- def files=(files)
- @@files = files
+ def add_tag(keyword)
+ @@tags << keyword
end
- def add_file(type, src, dest)
- @@files << { :type => type, :src => src, :dest => dest }
+ def to_yaml
+ {
+ :name => name,
+ :description => description,
+ :base_url => adjusted_base_url,
+ :blog_post => blog_post,
+ :files => files,
+ :screenshot => screenshot,
+ :tags => tags,
+ :parameter_example => parameter_example
+ }.to_yaml
end
- def base_url
- @@base_url
+ def adjusted_base_url
+ if base_url =~ /github.com\/(\w+\/\w+)\/(tree|blob)\/(.*)$/
+ "https://github.com/#{$1}/raw/#{$3}"
+ elsif base_url =~ /github.com\/(\w+\/\w+)\/?$/
+ "https://github.com/#{$1}/raw/master"
+ else
+ base_url
+ end
end
- def base_url=(url)
- @@base_url = url
+ def valid?
+ has_name? && has_description? && has_base_url? && has_screenshot? && all_template_files_exist?
end
- def to_yaml
- { :base_url => base_url, :files => files }.to_yaml
+ def has_name?
+ has_string_value?(:name)
end
+
+ def has_description?
+ has_string_value?(:description)
+ end
+
+ def has_base_url?
+ has_string_value?(:base_url)
+ end
+
+ def has_string_value?(value)
+ val = send(value)
+ valid = (val && val != '')
+ errors.push("Error: missing scaffold #{value}.") unless valid
+ valid
+ end
+
+ def has_screenshot?
+ has_string_value?(:screenshot) && remote_file_exists?(File.join(adjusted_base_url, screenshot))
+ end
+
+ def all_template_files_exist?
+ files.all? { |file| remote_file_exists?(File.join(adjusted_base_url, file[:src])) }
+ end
+
+ def remote_file_exists?(url)
+ valid = RemoteFile.new(url).exists?
+ errors.push("Error: unable to access remote URL #{url}") unless valid
+ valid
+ end
end
- def initialize
- yield self
+ def initialize(&block)
+ @context_stack = []
+ @context_options = {}
+ instance_eval(&block) if block_given?
end
- def method_missing(name, *args, &blk)
- if name.to_s =~ /(.*)_file/ && args[0].is_a?(Hash)
- self.class.add_file($1, args[0][:src], args[0][:dest])
- elsif name == :base_url
- self.class.base_url = args[0]
+ def with_options(options, &block)
+ @context_stack.push(@context_options)
+ @context_options = options_relative_to_parent(@context_options, options)
+ yield if block_given?
+ @context_options = @context_stack.pop
+ end
+
+ def metadata
+ yield if block_given?
+ end
+
+ def file(src, options = {}, type = :file)
+ self.class.add_file(
+ join_with_parent(@context_options[:src], src),
+ join_with_parent(@context_options[:dest], options[:dest]),
+ type
+ )
+ end
+
+ def template(src, options = {})
+ raise ':dest option is required for templates' unless options[:dest]
+ file(src, options, :template)
+ end
+
+ def tag(keyword)
+ self.class.add_tag(keyword)
+ end
+
+ protected
+
+ def join_with_parent(parent_value, new_value)
+ if parent_value && new_value
+ File.join(parent_value, new_value)
+ else
+ parent_value || new_value
end
end
+ def options_relative_to_parent(parent_options, options)
+ {
+ :src => join_with_parent(parent_options[:src], options[:src]),
+ :dest => join_with_parent(parent_options[:dest], options[:dest])
+ }
+ end
end
end