diff --git a/hammer/hammer.rb b/hammer/hammer.rb index 84d5fd4..e965f2f 100644 --- a/hammer/hammer.rb +++ b/hammer/hammer.rb @@ -67,9 +67,44 @@ def get_mime_type WEBrick::HTTPUtils::mime_type(@filesystem_path.to_s, mime_file) end - def self.error(message) - puts "Hammer Error: #{message.gsub!(/(<[^>]*>)|\n|\t/s) {""}}".colorize(:red) - return "Hammer Error: #{message}" + def self.error(message, options={}) + options = { + comment: false, + message: "", + warning: false + }.merge(options) + + type = options[:warning] ? "Warning" : "Error" + + error_background_color = options[:warning] ? "#9BD3DD" : "red" + error_text_color = options[:warning] ? "black" : "white" + span_style = "color: #000; border: 1px dashed #{error_background_color}; background-color: #fff; border-radius: 3px; font-family: monospace; padding: 0 3px 0 0;" + error_style= "color: #{error_text_color}; background-color: #{error_background_color}; border-radius: 3px 0 0 3px; padding: 0 3px; font-family: monospace;" + + console_error = "Hammer #{type}: #{message.gsub(/(<[^>]*>)|\n|\t/s) {""}}" + puts console_error.colorize(:red) + + error = "Hammer #{type}: #{message}" + if options[:comment] + "" + else + "#{error} #{options[:message]}" + end + end + + def self.key_missing(key,options={}) + options = { + parent_key: nil, + comment: false, + message: "" + }.merge(options) + + style = "background-color: #eee; border-radius: 3px; font-family: monospace; padding: 0 3px;" + if options[:parent_key] + error("Missing key #{key}: under #{options[:parent_key]}: in mock_data.yml", options) + else + error("Missing key #{key}: in mock_data.yml", options) + end end end diff --git a/hammer/services/dentaku_ext.rb b/hammer/services/dentaku_ext.rb new file mode 100644 index 0000000..0982ba0 --- /dev/null +++ b/hammer/services/dentaku_ext.rb @@ -0,0 +1,36 @@ +module Dentaku + module CustomFunctions + FUNCTIONS = [ + [ + :length, + :numeric, + ->(str) { str.length } + ], + [ + :blank, + :logical, + ->(str) { str.blank? } + ], + [ + :contains, + :logical, + ->(mainStr, subStr) { mainStr.include?(subStr) } + ], + [ + :startswith, + :logical, + ->(mainStr, subStr) { mainStr.starts_with?(subStr) } + ], + [ + :endswith, + :logical, + ->(mainStr, subStr) { mainStr.ends_with?(subStr) } + ], + [ + :matches, + :logical, + ->(str, regexStr) { !Regexp.new(regexStr).match(str).nil? } + ] + ] + end +end diff --git a/hammer/services/tag_binding.rb b/hammer/services/tag_binding.rb index b15ba5e..fc2a75a 100644 --- a/hammer/services/tag_binding.rb +++ b/hammer/services/tag_binding.rb @@ -1,9 +1,11 @@ require 'dentaku' +require '../hammer/services/dentaku_ext.rb' module Radius class TagBinding CALCULATOR = Dentaku::Calculator.new + CALCULATOR.add_functions(Dentaku::CustomFunctions::FUNCTIONS) # Evaluates the current tag and returns the rendered contents. def expand(newcontext=nil,oldcontext=nil) @@ -36,7 +38,7 @@ def attributes begin memo[k] = parse_value(v) rescue Exception => e - memo[k] = Hammer.error "Attribute Error #{name} #{e}" + Hammer.error "Attribute Error #{k} #{e}" #raise AttributeParseError.new(name, k, v, e.backtrace) end @@ -112,7 +114,8 @@ def math_dictionary memo end end - + # This method is used to parse tag attributes that may refer to variables or + # other tags def parse_value(v) str = v.to_s.strip if str =~ /^{\s*\$(\w+)\s*}$/ @@ -129,5 +132,6 @@ def parse_value(v) v end end + end end diff --git a/hammer/services/tags/asset.rb b/hammer/services/tags/asset.rb index ef41278..583e217 100644 --- a/hammer/services/tags/asset.rb +++ b/hammer/services/tags/asset.rb @@ -22,32 +22,19 @@ class Asset < TagContainer %w(id title name alt_text description).each do |mthd| tag "file:#{mthd}" do |tag| tag.locals.asset[mthd.to_sym] - #Hammer.error "file:#{mthd} tag is not implemented yet" end end tag 'file:filename' do |tag| - # tag.locals.asset.try(:filename) - asset = tag.locals.asset - #Hammer.error "file:filename tag is not implemented yet" - asset[:filename] + tag.locals.asset[:filename] end tag 'file:download_url' do |tag| - asset = tag.locals.asset - # asset.public_download_url - #Hammer.error "file:download_url tag is not implemented yet" - asset[:download_url] + tag.locals.asset[:download_url] end tag 'file:image_url' do |tag| - asset = tag.locals.asset - # size = tag.attr['size'] - # - # if asset.is_a?(ImageAsset) - # asset.image_url(size) - # end - asset[:image_url] + tag.locals.asset[:image_url] end @@ -59,73 +46,61 @@ class Asset < TagContainer %w(id class alt title).each do |opt| options[opt.to_sym] = tag.attr[opt] if tag.attr.has_key?(opt) end - # - # if asset.is_a?(ImageAsset) + options[:alt] ||= asset[:alt_text] - # asset.image_tag(size, options) - # end - #Hammer.error "file:image_tag is not implemented yet" - content_tag :img, { :src=>asset[:image_url], :id => options[:id], :class => options[:class], :alt => options[:alt], :title => options[:title]} + content_tag :img, { + src: asset[:image_url], + id: options[:id], + class: options[:class], + alt: options[:alt], + title: options[:title] + } end - # tag 'files' do |tag| - # tag.locals.assets = find_with_options(tag, tag.globals.site.assets) - # tag.expand - if tag.globals.context.data && tag.globals.context.data['files'] + if tag.globals.context.data['files'] tag.expand + else + Hammer.key_missing "files" end - - #Hammer.error "files tag is not implemented yet" end tag 'files:count' do |tag| - # count_items tag, tag.locals.assets - if tag.globals.context.data && tag.globals.context.data['files'] - files = tag.globals.context.data['files'] - loop_over(tag, files, false).count - end + tag.globals.context.data['files'].count end tag 'files:each' do |tag| - # loop_over tag, tag.locals.assets - if tag.globals.context.data && tag.globals.context.data['files'] - #loop_over tag, tag.globals.context.data['files'] - files = tag.globals.context.data['files'] - loop_over tag, files - end - - #Hammer.error "files:each tag is not implemented yet" + loop_over tag, tag.globals.context.data['files'] end - # def self.decorated_asset(asset) - # unless asset.is_a? ApplicationDecorator - # AssetDecorator.decorate(asset) - # end - # end + def self.decorated_asset(asset) + # unless asset.is_a? ApplicationDecorator + # AssetDecorator.decorate(asset) + # end + end def self.find_with_options(tag, target) conditions = tag.attr.symbolize_keys filter = { - :title => conditions[:title], - :types => conditions[:types] || [], - :tags => conditions[:labels] || [], - :tags_op => conditions[:labels_match] || 'any', - :order => conditions[:by] || 'name', - :reverse_order => conditions[:order] == 'desc' ? '1' : '0', - :random => conditions[:random].to_s.to_b, - :page => conditions[:offset].present? ? conditions[:offset].to_i : 1, - :limit => conditions[:limit].present? ? conditions[:limit].to_i : 50 + title: conditions[:title], + types: conditions[:types] || [], + tags: conditions[:labels] || [], + tags_op: conditions[:labels_match] || 'any', + order: conditions[:by] || 'name', + reverse_order: conditions[:order] == 'desc' ? '1' : '0', + random: conditions[:random].to_s.to_b, + page: conditions[:offset].present? ? conditions[:offset].to_i : 1, + limit: conditions[:limit].present? ? conditions[:limit].to_i : 50 } # assets = Filter::Assets.new(target, filter).all end def self.count_items(tag, target) - items = find_with_options(tag, target) - items.reorder(nil).count # Order is irrelevant for counting + # items = find_with_options(tag, target) + # items.reorder(nil).count # Order is irrelevant for counting end def self.loop_over(tag, target, out=true) diff --git a/hammer/services/tags/basic.rb b/hammer/services/tags/basic.rb index a8134cd..ff542c8 100644 --- a/hammer/services/tags/basic.rb +++ b/hammer/services/tags/basic.rb @@ -42,7 +42,7 @@ class Basic < TagContainer if tag.globals.context.data && tag.globals.context.data['site'] && tag.globals.context.data['site'][attr.to_s] tag.globals.context.data['site'][attr.to_s] else - Hammer.error "Missing key #{attr} under site:" + Hammer.key_missing attr, {parent_key: "site"} end end end @@ -56,7 +56,7 @@ class Basic < TagContainer if tag.globals.context.data && tag.globals.context.data['site'] && tag.globals.context.data['site']['data'] && tag.globals.context.data['site']['data'][attr] tag.globals.context.data['site']['data'][attr] else - Hammer.error "Missing key #{attr} under site:data" + Hammer.key_missing attr, {parent_key: "site:data"} end end diff --git a/hammer/services/tags/blog.rb b/hammer/services/tags/blog.rb index c444375..feaf12e 100644 --- a/hammer/services/tags/blog.rb +++ b/hammer/services/tags/blog.rb @@ -34,19 +34,35 @@ def initialize end tag 'article:id' do |tag| - tag.locals.article['id'] + if tag.locals.article['id'] + tag.locals.article['id'] + else + Hammer.key_missing "id", {parent_key: "article"} + end end tag 'article:name' do |tag| - tag.locals.article['name'] + if tag.locals.article['name'] + tag.locals.article['name'] + else + Hammer.key_missing "name", {parent_key: "article"} + end end tag 'article:title' do |tag| - tag.locals.article['title'] + if tag.locals.article['title'] + tag.locals.article['title'] + else + Hammer.key_missing "title", {parent_key: "article"} + end end tag 'article:path' do |tag| - tag.render 'page:url', tag.attr + if tag.locals.article['url'] + tag.locals.article['url'] + else + tag.render 'page:url', tag.attr + end end tag 'article:content' do |tag| @@ -54,48 +70,66 @@ def initialize tag.locals.article[:content] end - # TODO: Use a different taggable attribute, such as 'tags', instead of 'labels'. - # I think labels should be used for admin purposes and 'tags' should be used - # for the public. tag 'article:tags' do |tag| # tag.locals.article.label_list.join(',') if tag.locals.article['tags'].kind_of?(Array) tag.locals.article['tags'].join(',') elsif - Hammer.error 'Article tags should be an array see Hammer Mock Data Wiki' + Hammer.error 'Article tags should be an array' end end tag 'article:published_at' do |tag| - tag.locals.article[:published_at] + if tag.locals.article[:published_at] + tag.locals.article[:published_at] + else + "#{(0..10).to_a.sample} days ago" + end end tag 'article:author_first_name' do |tag| - tag.locals.article[:created_by][:first_name] + if tag.locals.article[:created_by][:first_name] + tag.locals.article[:created_by][:first_name] + else + Hammer.key_missing "first_name", {parent_key: "article"} + end end tag 'article:author_last_name' do |tag| - tag.locals.article[:created_by][:last_name] + if tag.locals.article[:created_by][:last_name] + tag.locals.article[:created_by][:last_name] + else + Hammer.key_missing "last_name", {parent_key: "article"} + end end tag 'article:author_full_name' do |tag| - tag.locals.article[:created_by][:first_name] + ' ' + tag.locals.article[:created_by][:last_name] + if tag.locals.article[:created_by] + if tag.locals.article[:created_by][:first_name] || tag.locals.article[:created_by][:last_name] + [tag.locals.article[:created_by][:first_name], tag.locals.article[:created_by][:last_name]].join(" ") + else + content = [] + content << (Hammer.key_missing "first_name or last_name", {parent_key: "article:created_by", comment: true, warning: true}) + content << [Faker::Name.first_name, Faker::Name.last_name].join(" ") + content.join("") + end + else + content = [] + content << (Hammer.key_missing "created_by", {parent_key: "article", comment: true}) + content << [Faker::Name.first_name, Faker::Name.last_name].join(" ") + content.join("") + end end tag 'articles' do |tag| - # tag.locals.blog ||= load_blog(tag) - # tag.locals.articles = filter_articles(tag, tag.locals.blog.children.published) - # tag.expand - - page_id = tag.globals.context.data['page']['id'] - articles = tag.globals.context.data['blog'].select{|w,v| w['id'] == page_id } - if articles.count > 0 - tag.locals.articles = articles.first['articles'] + + tag.locals.blog ||= load_blog(tag) + if tag.locals.blog['articles'] + tag.locals.articles = tag.locals.blog['articles'] + tag.expand else - tag.locals.articles = [] + Hammer.key_missing "articles", {parent_key: "blog"} end - tag.expand - end tag 'articles:each' do |tag| @@ -116,7 +150,7 @@ def initialize tag 'articles:if_no_articles' do |tag| # cnt = tag.locals.articles.try(:all).try(:count) # tag.expand if cnt.nil? or cnt == 0 - if tag.locals.articles.count.nil? or tag.locals.articles.count == 0 + if tag.locals.articles.count.nil? || tag.locals.articles.count == 0 tag.expand end end @@ -227,51 +261,55 @@ def gather_options(tag, defaults = {}) end def load_blog(tag) - # page = if tag.attr['id'].present? - # tag.globals.site.pages.find(tag.attr['id']) rescue nil - # else - # tag.locals.page - # end - # - # if page.type == 'ArticlePage' - # page = page.parent - # elsif page.type != 'BlogPage' - # page = nil - # end - # - # decorated_page(page) - if tag.globals.context.data && tag.globals.context.data['blog'].kind_of?(Array) - if tag.attr['id'] - tag.locals.blog = tag.globals.context.data['blog'].select{|w,v| w['id'].to_s ==(tag.attr['id']) }.first + tag.locals.errors = [] + if tag.globals.context.data['page'] + tag.locals.page = tag.globals.context.data['page'] + else + tag.locals.errors << (Hammer.key_missing "page") + end + + blogs = tag.globals.context.data['blogs'] || tag.globals.context.data['blog'] + + if tag.globals.context.data['blog'] + tag.locals.errors << (Hammer.error "Depreciation Notice: blog: key to be renamed blogs: in future release", {comment: true, warning: true}) + end + if blogs + if blogs.kind_of?(Array) + if blogs.select{|w| w['id'].to_s == (tag.locals.page['id'].to_s) }.first + tag.locals.blog = blogs.select{|w| w['id'].to_s == (tag.locals.page['id'].to_s) }.first + else + tag.locals.errors << (Hammer.error "Could not find blog with id: #{tag.locals.page['id']} in mock_data.yml") + end else - tag.locals.blog = tag.globals.context.data['blog'].first + tag.locals.errors << (Hammer.error "Depreciation Notice: in future release blogs: should be an Array in mock_data.yml", {comment: true, warning: true}) + tag.locals.blog = tag.globals.context.data['blog'] end else - Hammer.error 'No Blog Found in Mock Data File' + tag.locals.errors << (Hammer.key_missing "blogs") end - end def load_article(tag) - if tag.globals.context.data && tag.globals.context.data['blog'] && tag.globals.context.data['blog'].first['articles'] - tag.globals.context.data['blog'].first['articles'].sample - else - content = <<-CONTENT -

#{Faker::Lorem.paragraph(2)}

-

#{Faker::Lorem.paragraph(5)}

-

#{Faker::Lorem.paragraph(3)}

- CONTENT - article = { - :name => Faker::Lorem.sentence(1), - :title => Faker::Lorem.sentence(1), - :created_by => { :first_name => Faker::Name.first_name, :last_name => Faker::Name.last_name }, - :content => content, - :published_at => Random.rand(11).to_s+ " days ago" - } - tag.locals.article = article - article - end + # if tag.globals.context.data && tag.globals.context.data['blog'] && tag.globals.context.data['blog'].first['articles'] + # tag.globals.context.data['blog'].first['articles'].sample + # else + # content = <<-CONTENT + #

#{Faker::Lorem.paragraph(2)}

+ #

#{Faker::Lorem.paragraph(5)}

+ #

#{Faker::Lorem.paragraph(3)}

+ # CONTENT + # article = { + # :name => Faker::Lorem.sentence(1), + # :title => Faker::Lorem.sentence(1), + # :created_by => { :first_name => Faker::Name.first_name, :last_name => Faker::Name.last_name }, + # :content => content, + # :published_at => Random.rand(11).to_s+ " days ago" + # } + # tag.locals.article = article + # article + # end + tag.locals.blog['articles'].sample end def decorated_page(page) diff --git a/hammer/services/tags/content.rb b/hammer/services/tags/content.rb index e923304..4a3b1ab 100644 --- a/hammer/services/tags/content.rb +++ b/hammer/services/tags/content.rb @@ -14,7 +14,7 @@ class Content < TagContainer tag.globals.content_for[name] else if tag.globals.yield.empty? - Hammer.error "No yield data. Are you displaying a layout?" + Hammer.error "No yield data. Are you trying to view a layout?" else tag.globals.yield end @@ -49,24 +49,38 @@ class Content < TagContainer end tag 'editable_region' do |tag| - if tag.globals.context.data - if tag.globals.context.data['editable_region'] && tag.globals.context.data['editable_region'][tag.attr['name']] - content = tag.globals.context.data['editable_region'][tag.attr['name']] + # if tag.globals.context.data + # if tag.globals.context.data['editable_region'] && tag.globals.context.data['editable_region'][tag.attr['name']] + # content = tag.globals.context.data['editable_region'][tag.attr['name']] + # else + # content = Hammer.error "Set data for key: #{tag.attr['name']} under editable_region in the mock_data file" + # end + # else + # content = Faker::Lorem.paragraph(rand(2..10)) + # end + # if tag.globals.context.data['show_editable_regions'] + # if tag.attr['scope'] == "site" + # "
"+content+"
" + # else + # "
"+content+"
" + # end + # else + # content + # end + rname = tag.attr["name"] + if tag.globals.context.data['editable_region'] + if tag.globals.context.data['editable_region'][rname] + tag.globals.context.data['editable_region'][rname] else - content = Hammer.error "Set data for key: #{tag.attr['name']} under editable_region in the mock_data file" + content = [] + content << (Hammer.key_missing rname, {parent_key: "editable_region", warning: true, message: "auto generated paragraph added below"}) + content << "

#{Faker::Lorem.paragraph(rand(2..10))}

" + content.join("") end else - content = Faker::Lorem.paragraph(rand(2..10)) - end - if tag.globals.context.data['show_editable_regions'] - if tag.attr['scope'] == "site" - "
"+content+"
" - else - "
"+content+"
" - end - else - content + Hammer.key_missing "editable_region" end + end # The contents of this tag will only be rendered/accessible in the editor. This could be used, for example, to @@ -75,7 +89,7 @@ class Content < TagContainer # templates, if desired. tag 'edit_mode_only' do |tag| # if tag.globals.mode == Slate::ViewModes::EDIT - if tag.globals.context.data && tag.globals.context.data['edit_mode'] == true + if tag.globals.context.data['edit_mode'] == true tag.expand end end diff --git a/hammer/services/tags/menus.rb b/hammer/services/tags/menus.rb index 1f9535c..d64bb0f 100644 --- a/hammer/services/tags/menus.rb +++ b/hammer/services/tags/menus.rb @@ -1,4 +1,4 @@ -module Tags +module Tags class Menus < TagContainer tag 'site_menu' do |tag| @@ -6,6 +6,7 @@ class Menus < TagContainer tag.globals.context.data['site_menu'] else <<-MENU + #{Hammer.key_missing "site_menu", { message: "auto generated menu inserted below"}}