radiant-snippets-extension 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. data/README.md +7 -0
  2. data/Rakefile +109 -0
  3. data/app/controllers/admin/snippets_controller.rb +8 -0
  4. data/app/helpers/admin/snippets_helper.rb +41 -0
  5. data/app/models/snippet.rb +23 -0
  6. data/app/views/admin/snippets/_form.html.haml +33 -0
  7. data/app/views/admin/snippets/edit.html.haml +9 -0
  8. data/app/views/admin/snippets/index.html.haml +33 -0
  9. data/app/views/admin/snippets/new.html.haml +7 -0
  10. data/app/views/admin/snippets/remove.html.haml +17 -0
  11. data/config/initializers/radiant_config.rb +3 -0
  12. data/config/locales/en.yml +16 -0
  13. data/config/routes.rb +5 -0
  14. data/cucumber.yml +1 -0
  15. data/features/admin/configuration.feature +9 -0
  16. data/features/admin/pagination.feature +27 -0
  17. data/features/admin/snippets_management.feature +82 -0
  18. data/features/step_definitions/admin/snippet_steps.rb +25 -0
  19. data/features/support/env.rb +11 -0
  20. data/features/support/paths.rb +22 -0
  21. data/lib/radiant-snippets-extension.rb +8 -0
  22. data/lib/snippet_tags.rb +80 -0
  23. data/lib/tasks/snippets_extension_tasks.rake +47 -0
  24. data/radiant-snippets-extension.gemspec +24 -0
  25. data/snippets_extension.rb +52 -0
  26. data/spec/ci/before_script +23 -0
  27. data/spec/ci/script +2 -0
  28. data/spec/controllers/admin/snippets_controller_spec.rb +110 -0
  29. data/spec/datasets/snippets_dataset.rb +38 -0
  30. data/spec/lib/radiant/admin_ui_spec.rb +33 -0
  31. data/spec/models/page_spec.rb +80 -0
  32. data/spec/models/snippet_spec.rb +59 -0
  33. data/spec/models/user_action_observer_spec.rb +28 -0
  34. data/spec/spec.opts +6 -0
  35. data/spec/spec_helper.rb +36 -0
  36. metadata +104 -0
data/README.md ADDED
@@ -0,0 +1,7 @@
1
+ # Snippets
2
+
3
+ Use Snippets as reusable bits of content.
4
+
5
+ This extension was pulled from the original core.
6
+
7
+ Created by Radiant CMS Development Team.
data/Rakefile ADDED
@@ -0,0 +1,109 @@
1
+ # Determine where the RSpec plugin is by loading the boot
2
+ unless defined? RADIANT_ROOT
3
+ ENV["RAILS_ENV"] = "test"
4
+ case
5
+ when ENV["RADIANT_ENV_FILE"]
6
+ require File.dirname(ENV["RADIANT_ENV_FILE"]) + "/boot"
7
+ when File.dirname(__FILE__) =~ %r{vendor/radiant/vendor/extensions}
8
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../../")}/config/boot"
9
+ else
10
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../")}/config/boot"
11
+ end
12
+ end
13
+
14
+ require 'rake'
15
+ require 'rdoc/task'
16
+ require 'rake/testtask'
17
+
18
+ rspec_base = File.expand_path(RADIANT_ROOT + '/vendor/plugins/rspec/lib')
19
+ $LOAD_PATH.unshift(rspec_base) if File.exist?(rspec_base)
20
+ require 'spec/rake/spectask'
21
+ require 'cucumber'
22
+ require 'cucumber/rake/task'
23
+
24
+ # Cleanup the RADIANT_ROOT constant so specs will load the environment
25
+ Object.send(:remove_const, :RADIANT_ROOT)
26
+
27
+ extension_root = File.expand_path(File.dirname(__FILE__))
28
+
29
+ task :default => [:spec, :features]
30
+ task :stats => "spec:statsetup"
31
+
32
+ desc "Run all specs in spec directory"
33
+ Spec::Rake::SpecTask.new(:spec) do |t|
34
+ t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
35
+ t.spec_files = FileList['spec/**/*_spec.rb']
36
+ end
37
+
38
+ task :features => 'spec:integration'
39
+
40
+ namespace :spec do
41
+ desc "Run all specs in spec directory with RCov"
42
+ Spec::Rake::SpecTask.new(:rcov) do |t|
43
+ t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
44
+ t.spec_files = FileList['spec/**/*_spec.rb']
45
+ t.rcov = true
46
+ t.rcov_opts = ['--exclude', 'spec', '--rails']
47
+ end
48
+
49
+ desc "Print Specdoc for all specs"
50
+ Spec::Rake::SpecTask.new(:doc) do |t|
51
+ t.spec_opts = ["--format", "specdoc", "--dry-run"]
52
+ t.spec_files = FileList['spec/**/*_spec.rb']
53
+ end
54
+
55
+ [:models, :controllers, :views, :helpers].each do |sub|
56
+ desc "Run the specs under spec/#{sub}"
57
+ Spec::Rake::SpecTask.new(sub) do |t|
58
+ t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
59
+ t.spec_files = FileList["spec/#{sub}/**/*_spec.rb"]
60
+ end
61
+ end
62
+
63
+ desc "Run the Cucumber features"
64
+ Cucumber::Rake::Task.new(:integration) do |t|
65
+ t.fork = true
66
+ t.cucumber_opts = ['--format', (ENV['CUCUMBER_FORMAT'] || 'pretty')]
67
+ # t.feature_pattern = "#{extension_root}/features/**/*.feature"
68
+ t.profile = "default"
69
+ end
70
+
71
+ # Setup specs for stats
72
+ task :statsetup do
73
+ require 'code_statistics'
74
+ ::STATS_DIRECTORIES << %w(Model\ specs spec/models)
75
+ ::STATS_DIRECTORIES << %w(View\ specs spec/views)
76
+ ::STATS_DIRECTORIES << %w(Controller\ specs spec/controllers)
77
+ ::STATS_DIRECTORIES << %w(Helper\ specs spec/views)
78
+ ::CodeStatistics::TEST_TYPES << "Model specs"
79
+ ::CodeStatistics::TEST_TYPES << "View specs"
80
+ ::CodeStatistics::TEST_TYPES << "Controller specs"
81
+ ::CodeStatistics::TEST_TYPES << "Helper specs"
82
+ ::STATS_DIRECTORIES.delete_if {|a| a[0] =~ /test/}
83
+ end
84
+
85
+ namespace :db do
86
+ namespace :fixtures do
87
+ desc "Load fixtures (from spec/fixtures) into the current environment's database. Load specific fixtures using FIXTURES=x,y"
88
+ task :load => :environment do
89
+ require 'active_record/fixtures'
90
+ ActiveRecord::Base.establish_connection(RAILS_ENV.to_sym)
91
+ (ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/) : Dir.glob(File.join(RAILS_ROOT, 'spec', 'fixtures', '*.{yml,csv}'))).each do |fixture_file|
92
+ Fixtures.create_fixtures('spec/fixtures', File.basename(fixture_file, '.*'))
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
98
+
99
+ desc 'Generate documentation for the snippets extension.'
100
+ RDoc::Task.new(:rdoc) do |rdoc|
101
+ rdoc.rdoc_dir = 'rdoc'
102
+ rdoc.title = 'SnippetsExtension'
103
+ rdoc.options << '--line-numbers' << '--inline-source'
104
+ rdoc.rdoc_files.include('README')
105
+ rdoc.rdoc_files.include('lib/**/*.rb')
106
+ end
107
+
108
+ # Load any custom rakefiles for extension
109
+ Dir[File.dirname(__FILE__) + '/tasks/*.rake'].sort.each { |f| require f }
@@ -0,0 +1,8 @@
1
+ class Admin::SnippetsController < Admin::ResourceController
2
+ paginate_models
3
+ only_allow_access_to :index, :show, :new, :create, :edit, :update, :remove, :destroy,
4
+ :when => [:designer, :admin],
5
+ :denied_url => { :controller => 'admin/pages', :action => 'index' },
6
+ :denied_message => 'You must have designer privileges to perform this action.'
7
+
8
+ end
@@ -0,0 +1,41 @@
1
+ module Admin::SnippetsHelper
2
+ def snippet_edit_javascripts
3
+ <<-CODE
4
+
5
+ var tagReferenceWindows = {};
6
+ function loadTagReference() {
7
+ var pageType = 'Page';
8
+ if (!tagReferenceWindows[pageType])
9
+ tagReferenceWindows[pageType] = new Popup.AjaxWindow("#{admin_reference_path('tags')}?class_name=" + encodeURIComponent(pageType), {reload: false});
10
+ var window = tagReferenceWindows[pageType];
11
+ if('Page' != pageType) {
12
+ $('tag_reference_link').highlight();
13
+ window.show();
14
+ } else {
15
+ window.toggle();
16
+ }
17
+ lastPageType = pageType;
18
+ return false;
19
+ }
20
+
21
+ var lastFilter = '#{@snippet.filter_id}';
22
+ var filterWindows = {};
23
+ function loadFilterReference() {
24
+ var filter = $F("snippet_filter_id");
25
+ if (filter != "") {
26
+ if (!filterWindows[filter]) filterWindows[filter] = new Popup.AjaxWindow("#{admin_reference_path('filters')}?filter_name="+encodeURIComponent(filter), {reload: false});
27
+ var window = filterWindows[filter];
28
+ if(lastFilter != filter) {
29
+ window.show();
30
+ } else {
31
+ window.toggle();
32
+ }
33
+ lastFilter = filter;
34
+ } else {
35
+ alert('No documentation for filter.');
36
+ }
37
+ return false;
38
+ }
39
+ CODE
40
+ end
41
+ end
@@ -0,0 +1,23 @@
1
+ class Snippet < ActiveRecord::Base
2
+
3
+ # Default Order
4
+ default_scope :order => 'name'
5
+
6
+ # Associations
7
+ belongs_to :created_by, :class_name => 'User'
8
+ belongs_to :updated_by, :class_name => 'User'
9
+
10
+ # Validations
11
+ validates_presence_of :name
12
+ validates_length_of :name, :maximum => 100
13
+ validates_length_of :filter_id, :maximum => 25, :allow_nil => true
14
+ validates_format_of :name, :with => %r{^\S*$}
15
+ validates_uniqueness_of :name
16
+
17
+ object_id_attr :filter, TextFilter
18
+
19
+ def after_initialize
20
+ self.filter_id ||= Radiant::Config['defaults.snippet.filter'] if new_record?
21
+ end
22
+
23
+ end
@@ -0,0 +1,33 @@
1
+ - form_for [:admin, @snippet], :html => {'data-onsubmit_status' => onsubmit_status(@snippet)} do |f|
2
+ = f.hidden_field :lock_version
3
+ = render_region :form_top, :locals => {:f => f}
4
+ .form_area
5
+ - render_region :form, :locals => {:f => f} do |form|
6
+ - form.edit_title do
7
+ %p.title
8
+ = f.label :name, t('name')
9
+ = f.text_field :name, :class => 'textbox activate', :maxlength => 100
10
+ - form.edit_content do
11
+ %p.content
12
+ = f.label :content, t('body')
13
+ ~ f.text_area :content, :class => "textarea large", :style => "width: 100%"
14
+ - form.edit_filter do
15
+ .set
16
+ %p
17
+ = f.label :filter_id, t('filter')
18
+ = f.select :filter_id, filter_options_for_select(f.object.filter_id), :id => 'snippet_filter'
19
+ %span.reference_links
20
+ == #{t('reference')}:
21
+ %span{:id => "filter_reference_link"}
22
+ = link_to_function t('filter'), "loadFilterReference();"
23
+ %span{:id => "tag_reference_link"}
24
+ = link_to_function t('available_tags'), "loadTagReference('Page');"
25
+ - render_region :form_bottom, :locals => {:f => f} do |form_bottom|
26
+ - form_bottom.edit_buttons do
27
+ .buttons{:style=>"clear: left"}
28
+ = save_model_button(@snippet)
29
+ = save_model_and_continue_editing_button(@snippet)
30
+ = t('or')
31
+ = link_to t('cancel'), admin_snippets_url
32
+ - form_bottom.edit_timestamp do
33
+ = updated_stamp @snippet
@@ -0,0 +1,9 @@
1
+ - @page_title = @snippet.name + ' ' + t('snippet') + ' - ' + default_page_title
2
+
3
+ - render_region :main do |main|
4
+ - main.edit_header do
5
+ %h1= t('edit_snippet')
6
+ - main.edit_form do
7
+ = render :partial => 'form'
8
+
9
+ - content_for 'page_scripts', snippet_edit_javascripts
@@ -0,0 +1,33 @@
1
+ - @page_title = t('snippets') + ' - ' + default_page_title
2
+
3
+ .outset
4
+ = render_region :top
5
+ %table.index#snippets
6
+ %thead
7
+ %tr
8
+ - render_region :thead do |thead|
9
+ - thead.title_header do
10
+ %th.name= t('snippet')
11
+ - thead.actions_header do
12
+ %th.actions{:style=>"width:9em"}= t('modify')
13
+ %tbody
14
+ - if @snippets.any?
15
+ - @snippets.each do |snippet|
16
+ %tr[snippet]
17
+ - render_region :tbody, :locals => {:snippet => snippet} do |tbody|
18
+ - tbody.title_cell do
19
+ %td.name
20
+ = link_to image('snippet', :alt => '') + ' ' + snippet.name, edit_admin_snippet_url(snippet)
21
+ - tbody.actions_cell do
22
+ %td.actions
23
+ = link_to image('minus') + ' ' + t('remove'), remove_admin_snippet_url(snippet), :class => "action"
24
+ - else
25
+ %tr
26
+ %td.empty{:colspan => admin.snippet.index.tbody.length}= t('no_snippets')
27
+
28
+ - render_region :bottom do |bottom|
29
+ - bottom.new_button do
30
+ #actions
31
+ = pagination_for(@snippets)
32
+ %ul
33
+ %li= link_to image('plus') + " " + t('new_snippet'), new_admin_snippet_url, :class => 'action_button'
@@ -0,0 +1,7 @@
1
+ - render_region :main do |main|
2
+ - main.edit_header do
3
+ %h1= t('new_snippet')
4
+ - main.edit_form do
5
+ = render :partial => 'form'
6
+
7
+ - content_for 'page_scripts', snippet_edit_javascripts
@@ -0,0 +1,17 @@
1
+ %h1= t('remove_snippet')
2
+
3
+ %p
4
+ = t('text.snippets.remove_warning')
5
+
6
+ %table.index#snippets
7
+ %tbody
8
+ %tr.node.level_1
9
+ %td.snippet
10
+ = image('snippet', :alt => "")
11
+ %span.title= @snippet.name
12
+
13
+ - form_for [:admin, @snippet], :html => {:method => :delete, 'data-onsubmit_status'=>"Removing snippet&#8230;"} do
14
+ .buttons
15
+ %input.button{:type=>"submit", :value => t('delete_snippet')}/
16
+ = t('or')
17
+ = link_to t('cancel'), admin_snippets_url
@@ -0,0 +1,3 @@
1
+ Radiant.config do |config|
2
+ # config.define "setting.name", :default => 'value', :select_from => ['foo', 'bar']
3
+ end
@@ -0,0 +1,16 @@
1
+ ---
2
+ en:
3
+ snippet: 'Snippet'
4
+ snippets: 'Snippets'
5
+ config:
6
+ defaults:
7
+ snippet:
8
+ filter: "snippet filter"
9
+ delete_snippet: 'Delete Snippet'
10
+ edit_snippet: 'Edit Snippet'
11
+ new_snippet: 'New Snippet'
12
+ no_snippets: 'No Snippets'
13
+ remove_snippet: 'Remove Snippet'
14
+ text:
15
+ snippets:
16
+ remove_warning: 'Are you sure you want to <strong class="warning">permanently remove</strong> the following snippet?'
data/config/routes.rb ADDED
@@ -0,0 +1,5 @@
1
+ ActionController::Routing::Routes.draw do |map|
2
+ map.namespace :admin, :member => { :remove => :get } do |admin|
3
+ admin.resources :snippets
4
+ end
5
+ end
data/cucumber.yml ADDED
@@ -0,0 +1 @@
1
+ default: --format progress features --tags ~@proposed,~@in_progress
@@ -0,0 +1,9 @@
1
+ Feature: Rich configuration
2
+ In order to control site delivery
3
+ an administrator
4
+ wants to change the configuration of the site
5
+
6
+ Scenario: Reviewing configuration
7
+ Given I am logged in as "admin"
8
+ And I go to the "configuration" admin page
9
+ Then I should see "Snippet Filter"
@@ -0,0 +1,27 @@
1
+ Feature: Paginating admin views
2
+ In order to reduce load time and page bulk
3
+ a content editor
4
+ wants longer resource lists to be paginated
5
+
6
+ Background:
7
+ Given There are many snippets
8
+ And I am logged in as "designer"
9
+ And I go to the "snippets" admin page
10
+
11
+ Scenario: More snippets than we want to show on one page
12
+ Then I should see "first"
13
+ And I should not see "snippet_50"
14
+ And I should see page 1 of the results
15
+ And I should see pagination controls
16
+ And I should see a depagination link
17
+
18
+ When I follow "2" within "div.pagination"
19
+ Then I should see page 2 of the results
20
+ And I should see "snippet_50"
21
+
22
+ When I follow "show all"
23
+ # Then I should mention the request parameters
24
+ Then I should see all the snippets
25
+ And I should not see pagination controls
26
+ And I should not see a depagination link
27
+
@@ -0,0 +1,82 @@
1
+ Feature: Managing snippets
2
+ In order to share content between layouts and pages, as a designer I want to
3
+ manage a collection of snippets
4
+
5
+ Background:
6
+ Given I am logged in as "designer"
7
+
8
+ Scenario: List snippets
9
+ When I follow "Design" within "#navigation"
10
+ And I follow "Snippets"
11
+ Then I should see "first"
12
+ And I should see "another"
13
+ And I should see "markdown"
14
+ # And a host of others
15
+
16
+ Scenario: Create a snippet
17
+ When I follow "Design" within "#navigation"
18
+ And I follow "Snippets"
19
+ And I follow "New Snippet"
20
+ And I fill in "Name" with "Mine"
21
+ And I fill in "Body" with "My snippet"
22
+ And I press "Create Snippet"
23
+ Then I should be on the snippets list
24
+ And I should see "Mine"
25
+
26
+ Scenario: Display form errors
27
+ When I follow "Design" within "#navigation"
28
+ And I follow "Snippets"
29
+ And I follow "New Snippet"
30
+ And I fill in "Body" with "My snippet"
31
+ And I press "Create Snippet"
32
+ Then I should see an error message
33
+ And I should see the form
34
+
35
+ Scenario: Continue editing
36
+ When I follow "Design" within "#navigation"
37
+ And I follow "Snippets"
38
+ And I follow "New Snippet"
39
+ And I fill in "Name" with "Mine"
40
+ And I fill in "Body" with "My snippet"
41
+ And I press "Save and Continue Editing"
42
+ Then I should see "Edit Snippet"
43
+ And I should see the form
44
+
45
+ Scenario: View a snippet
46
+ When I view a filtered snippet
47
+ Then I should see "Edit Snippet"
48
+ And I should see "Markdown"
49
+
50
+ Scenario: Delete a snippet with confirmation
51
+ When I follow "Design" within "#navigation"
52
+ And I follow "Snippets"
53
+ And I follow "Remove"
54
+ Then I should see "permanently remove"
55
+ And I should see "another"
56
+ When I press "Delete Snippet"
57
+ Then I should not see "another"
58
+
59
+ Scenario Outline: Admins and designers can see and edit snippets
60
+ Given I am logged in as "<username>"
61
+ And I should see "Design"
62
+ When I follow "Design" within "#navigation"
63
+ And I follow "Snippets"
64
+ And I should not see "You must have designer privileges"
65
+ And I follow "first"
66
+ Then I should see "Edit Snippet"
67
+
68
+ Examples:
69
+ | username |
70
+ | admin |
71
+ | designer |
72
+
73
+ Scenario Outline: Ordinary users cannot edit snippets
74
+ Given I am logged in as "<username>"
75
+ And I should not see "Design"
76
+ When I go to the "snippets" admin page
77
+ Then I should see "You must have designer privileges"
78
+
79
+ Examples:
80
+ | username |
81
+ | existing |
82
+ | another |
@@ -0,0 +1,25 @@
1
+ Given /^There are many snippets$/ do
2
+ 100.times do |i|
3
+ Snippet.create(:name => "snippet_#{i}", :content => "This is snippet #{i}")
4
+ end
5
+ end
6
+
7
+ Given /^There are few snippets$/ do
8
+ #
9
+ end
10
+
11
+ Then /^I should see all the snippets$/ do
12
+ Snippet.all.each do |snippet|
13
+ response.body.should have_tag('tr.snippet') do
14
+ with_tag("a", :text => snippet.name)
15
+ end
16
+ end
17
+ end
18
+
19
+ When /^I view a snippet$/ do
20
+ visit "/admin/snippets/#{snippets(:first).id}"
21
+ end
22
+
23
+ When /^I view a filtered snippet$/ do
24
+ visit "/admin/snippets/#{snippets(:markdown).id}"
25
+ end
@@ -0,0 +1,11 @@
1
+ # Sets up the Rails environment for Cucumber
2
+ ENV["RAILS_ENV"] = "test"
3
+ # Extension root
4
+ extension_env = File.expand_path(File.dirname(__FILE__) + '/../../../../../config/environment')
5
+ require extension_env+'.rb'
6
+
7
+ Dir.glob(File.join(RADIANT_ROOT, "features", "**", "*.rb")).each {|step| require step unless step =~ /datasets_loader\.rb$/}
8
+
9
+ Cucumber::Rails::World.class_eval do
10
+ dataset :snippets
11
+ end
@@ -0,0 +1,22 @@
1
+ module NavigationHelpers
2
+
3
+ # Extend the standard PathMatchers with your own paths
4
+ # to be used in your features.
5
+ #
6
+ # The keys and values here may be used in your standard web steps
7
+ # Using:
8
+ #
9
+ # When I go to the "snippets" admin page
10
+ #
11
+ # would direct the request to the path you provide in the value:
12
+ #
13
+ # admin_snippets_path
14
+ #
15
+ PathMatchers = {} unless defined?(PathMatchers)
16
+ PathMatchers.merge!({
17
+ /snippets/i => 'admin_snippets_path'
18
+ })
19
+
20
+ end
21
+
22
+ World(NavigationHelpers)
@@ -0,0 +1,8 @@
1
+ module RadiantSnippetsExtension
2
+ VERSION = "1.0.0"
3
+ SUMMARY = "Snippets for Radiant CMS"
4
+ DESCRIPTION = "Makes Radiant better by adding snippets!"
5
+ URL = "http://github.com/radiant"
6
+ AUTHORS = ["Jim Gay"]
7
+ EMAIL = ["radiant@radiantcms.org"]
8
+ end
@@ -0,0 +1,80 @@
1
+ module SnippetTags
2
+ include Radiant::Taggable
3
+
4
+ class TagError < StandardError; end
5
+
6
+ desc %{
7
+ Renders the snippet specified in the @name@ attribute within the context of a page.
8
+
9
+ *Usage:*
10
+
11
+ <pre><code><r:snippet name="snippet_name" /></code></pre>
12
+
13
+ When used as a double tag, the part in between both tags may be used within the
14
+ snippet itself, being substituted in place of @<r:yield/>@.
15
+
16
+ *Usage:*
17
+
18
+ <pre><code><r:snippet name="snippet_name">Lorem ipsum dolor...</r:snippet></code></pre>
19
+ }
20
+ tag 'snippet' do |tag|
21
+ required_attr(tag, 'name')
22
+ name = tag['name']
23
+
24
+ snippet = snippet_cache(name.strip)
25
+
26
+ if snippet
27
+ tag.locals.yield = tag.expand if tag.double?
28
+ tag.globals.page.render_snippet(snippet)
29
+ else
30
+ raise TagError.new("snippet '#{name}' not found")
31
+ end
32
+ end
33
+
34
+ def snippet_cache(name)
35
+ @snippet_cache ||= {}
36
+
37
+ snippet = @snippet_cache[name]
38
+ unless snippet
39
+ snippet = Snippet.find_by_name(name)
40
+ @snippet_cache[name] = snippet
41
+ end
42
+ snippet
43
+ end
44
+ private :snippet_cache
45
+
46
+ desc %{
47
+ Used within a snippet as a placeholder for substitution of child content, when
48
+ the snippet is called as a double tag.
49
+
50
+ *Usage (within a snippet):*
51
+
52
+ <pre><code>
53
+ <div id="outer">
54
+ <p>before</p>
55
+ <r:yield/>
56
+ <p>after</p>
57
+ </div>
58
+ </code></pre>
59
+
60
+ If the above snippet was named "yielding", you could call it from any Page,
61
+ Layout or Snippet as follows:
62
+
63
+ <pre><code><r:snippet name="yielding">Content within</r:snippet></code></pre>
64
+
65
+ Which would output the following:
66
+
67
+ <pre><code>
68
+ <div id="outer">
69
+ <p>before</p>
70
+ Content within
71
+ <p>after</p>
72
+ </div>
73
+ </code></pre>
74
+
75
+ When called in the context of a Page or a Layout, @<r:yield/>@ outputs nothing.
76
+ }
77
+ tag 'yield' do |tag|
78
+ tag.locals.yield
79
+ end
80
+ end
@@ -0,0 +1,47 @@
1
+ namespace :radiant do
2
+ namespace :extensions do
3
+ namespace :snippets do
4
+
5
+ desc "Runs the migration of the Snippets extension"
6
+ task :migrate => :environment do
7
+ require 'radiant/extension_migrator'
8
+ if ENV["VERSION"]
9
+ SnippetsExtension.migrator.migrate(ENV["VERSION"].to_i)
10
+ Rake::Task['db:schema:dump'].invoke
11
+ else
12
+ SnippetsExtension.migrator.migrate
13
+ Rake::Task['db:schema:dump'].invoke
14
+ end
15
+ end
16
+
17
+ desc "Copies public assets of the Snippets to the instance public/ directory."
18
+ task :update => :environment do
19
+ is_svn_or_dir = proc {|path| path =~ /\.svn/ || File.directory?(path) }
20
+ puts "Copying assets from SnippetsExtension"
21
+ Dir[SnippetsExtension.root + "/public/**/*"].reject(&is_svn_or_dir).each do |file|
22
+ path = file.sub(SnippetsExtension.root, '')
23
+ directory = File.dirname(path)
24
+ mkdir_p RAILS_ROOT + directory, :verbose => false
25
+ cp file, RAILS_ROOT + path, :verbose => false
26
+ end
27
+ end
28
+
29
+ desc "Syncs all available translations for this ext to the English ext master"
30
+ task :sync => :environment do
31
+ # The main translation root, basically where English is kept
32
+ language_root = SnippetsExtension.root + "/config/locales"
33
+ words = TranslationSupport.get_translation_keys(language_root)
34
+
35
+ Dir["#{language_root}/*.yml"].each do |filename|
36
+ next if filename.match('_available_tags')
37
+ basename = File.basename(filename, '.yml')
38
+ puts "Syncing #{basename}"
39
+ (comments, other) = TranslationSupport.read_file(filename, basename)
40
+ words.each { |k,v| other[k] ||= words[k] } # Initializing hash variable as empty if it does not exist
41
+ other.delete_if { |k,v| !words[k] } # Remove if not defined in en.yml
42
+ TranslationSupport.write_file(filename, basename, comments, other)
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "radiant-snippets-extension"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "radiant-snippets-extension"
7
+ s.version = RadiantSnippetsExtension::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = RadiantSnippetsExtension::AUTHORS
10
+ s.email = RadiantSnippetsExtension::EMAIL
11
+ s.homepage = RadiantSnippetsExtension::URL
12
+ s.summary = RadiantSnippetsExtension::SUMMARY
13
+ s.description = RadiantSnippetsExtension::DESCRIPTION
14
+
15
+ ignores = if File.exist?('.gitignore')
16
+ File.read('.gitignore').split("\n").inject([]) {|a,p| a + Dir[p] }
17
+ else
18
+ []
19
+ end
20
+ s.files = Dir['**/*'] - ignores
21
+ s.test_files = Dir['test/**/*','spec/**/*','features/**/*'] - ignores
22
+ # s.executables = Dir['bin/*'] - ignores
23
+ s.require_paths = ["lib"]
24
+ end
@@ -0,0 +1,52 @@
1
+ # Uncomment this if you reference any of your controllers in activate
2
+ # require_dependency "application_controller"
3
+ require "radiant-snippets-extension"
4
+
5
+ class SnippetsExtension < Radiant::Extension
6
+ version RadiantSnippetsExtension::VERSION
7
+ description RadiantSnippetsExtension::DESCRIPTION
8
+ url RadiantSnippetsExtension::URL
9
+
10
+ def activate
11
+
12
+ if defined?(Radiant::Exporter)
13
+ Radiant::Exporter.exportable_models << Snippet
14
+ Radiant::Exporter.template_models << Snippet
15
+ end
16
+
17
+ Page.class_eval do
18
+ include SnippetTags
19
+ end
20
+
21
+ Radiant::AdminUI.class_eval do
22
+ attr_accessor :snippet
23
+ alias_method :snippets, :snippet
24
+
25
+ def load_default_snippet_regions
26
+ OpenStruct.new.tap do |snippet|
27
+ snippet.edit = Radiant::AdminUI::RegionSet.new do |edit|
28
+ edit.main.concat %w{edit_header edit_form}
29
+ edit.form.concat %w{edit_title edit_content edit_filter}
30
+ edit.form_bottom.concat %w{edit_buttons edit_timestamp}
31
+ end
32
+ snippet.index = Radiant::AdminUI::RegionSet.new do |index|
33
+ index.top.concat %w{}
34
+ index.thead.concat %w{title_header actions_header}
35
+ index.tbody.concat %w{title_cell actions_cell}
36
+ index.bottom.concat %w{new_button}
37
+ end
38
+ snippet.new = snippet.edit
39
+ end
40
+ end
41
+ end
42
+
43
+ admin.snippet ||= Radiant::AdminUI.load_default_snippet_regions
44
+
45
+ UserActionObserver.instance.send :add_observer!, Snippet
46
+
47
+ tab 'Design' do
48
+ add_item "Snippets", "/admin/snippets"
49
+ end
50
+
51
+ end
52
+ end
@@ -0,0 +1,23 @@
1
+ cd ~
2
+ git clone git://github.com/radiant/radiant.git
3
+ cd ~/radiant
4
+ if [[ $RADIANT_VERSION != "master" ]]
5
+ then
6
+ git checkout -b $RADIANT_VERSION $RADIANT_VERSION
7
+ fi
8
+ cp -r ~/builds/*/radiant-snippets-extension vendor/extensions/snippets
9
+ gem install bundler --pre
10
+ echo 'gem "radiant-snippets-extension", :path => "vendor/extensions/snippets"' >> Gemfile
11
+ bundle install
12
+
13
+ case $DB in
14
+ "mysql" )
15
+ mysql -e 'create database radiant_test;'
16
+ cp spec/ci/database.mysql.yml config/database.yml;;
17
+ "postgres" )
18
+ psql -c 'create database radiant_test;' -U postgres
19
+ cp spec/ci/database.postgresql.yml config/database.yml;;
20
+ esac
21
+
22
+ bundle exec rake db:migrate
23
+ bundle exec rake db:migrate:extensions
data/spec/ci/script ADDED
@@ -0,0 +1,2 @@
1
+ cd ~/radiant
2
+ bundle exec rake spec:extensions EXT=snippets
@@ -0,0 +1,110 @@
1
+ require File.dirname(__FILE__) + "/../../spec_helper"
2
+
3
+ describe Admin::SnippetsController do
4
+ dataset :users, :snippets
5
+
6
+ before :each do
7
+ ActionController::Routing::Routes.reload
8
+ login_as :designer
9
+ end
10
+
11
+ it "should be an ResourceController" do
12
+ controller.should be_kind_of(Admin::ResourceController)
13
+ end
14
+
15
+ it "should handle Snippets" do
16
+ controller.class.model_class.should == Snippet
17
+ end
18
+
19
+
20
+ describe "show" do
21
+ it "should redirect to the edit action" do
22
+ get :show, :id => 1
23
+ response.should redirect_to(edit_admin_snippet_path(params[:id]))
24
+ end
25
+
26
+ it "should show xml when format is xml" do
27
+ snippet = Snippet.first
28
+ get :show, :id => snippet.id, :format => "xml"
29
+ response.body.should == snippet.to_xml
30
+ end
31
+ end
32
+
33
+ describe "with invalid snippet id" do
34
+ [:edit, :remove].each do |action|
35
+ before do
36
+ @parameters = {:id => 999}
37
+ end
38
+ it "should redirect the #{action} action to the index action" do
39
+ get action, @parameters
40
+ response.should redirect_to(admin_snippets_path)
41
+ end
42
+ it "should say that the 'Snippet could not be found.' after the #{action} action" do
43
+ get action, @parameters
44
+ flash[:notice].should == 'Snippet could not be found.'
45
+ end
46
+ end
47
+ it 'should redirect the update action to the index action' do
48
+ put :update, @parameters
49
+ response.should redirect_to(admin_snippets_path)
50
+ end
51
+ it "should say that the 'Snippet could not be found.' after the update action" do
52
+ put :update, @parameters
53
+ flash[:notice].should == 'Snippet could not be found.'
54
+ end
55
+ it 'should redirect the destroy action to the index action' do
56
+ delete :destroy, @parameters
57
+ response.should redirect_to(admin_snippets_path)
58
+ end
59
+ it "should say that the 'Snippet could not be found.' after the destroy action" do
60
+ delete :destroy, @parameters
61
+ flash[:notice].should == 'Snippet could not be found.'
62
+ end
63
+ end
64
+
65
+ {:get => [:index, :show, :new, :edit, :remove],
66
+ :post => [:create],
67
+ :put => [:update],
68
+ :delete => [:destroy]}.each do |method, actions|
69
+ actions.each do |action|
70
+ it "should require login to access the #{action} action" do
71
+ logout
72
+ lambda { send(method, action, :id => snippet_id(:first)) }.should require_login
73
+ end
74
+
75
+ if action == :show
76
+ it "should request authentication for API access on show" do
77
+ logout
78
+ send(method, action, :id => snippet_id(:first), :format => "xml")
79
+ response.response_code.should == 401
80
+ end
81
+ else
82
+ it "should allow access to designers for the #{action} action" do
83
+ lambda {
84
+ send(method, action, :id => snippet_id(:first))
85
+ }.should restrict_access(:allow => [users(:designer)],
86
+ :url => '/admin/pages')
87
+ end
88
+
89
+ it "should allow access to admins for the #{action} action" do
90
+ lambda {
91
+ send(method, action, :id => snippet_id(:first))
92
+ }.should restrict_access(:allow => [users(:designer)],
93
+ :url => '/admin/pages')
94
+ end
95
+
96
+ it "should deny non-designers and non-admins for the #{action} action" do
97
+ lambda {
98
+ send(method, action, :id => Snippet.first.id)
99
+ }.should restrict_access(:deny => [users(:non_admin), users(:existing)],
100
+ :url => '/admin/pages')
101
+ end
102
+ end
103
+ end
104
+ end
105
+
106
+ it "should clear the page cache when saved" do
107
+ Radiant::Cache.should_receive(:clear)
108
+ put :update, :id => snippet_id(:first), :snippet => {:content => "Foobar."}
109
+ end
110
+ end
@@ -0,0 +1,38 @@
1
+ class SnippetsDataset < Dataset::Base
2
+
3
+ def load
4
+ create_snippet "first", :content => "test"
5
+ create_snippet "another", :content => "another test"
6
+ create_snippet "markdown", :filter_id => "Markdown", :content => "**markdown**"
7
+ create_snippet "radius", :content => "<r:title />"
8
+ create_snippet "global_page_cascade", :content => "<r:children:each><r:page:title /> </r:children:each>"
9
+ create_snippet "recursive", :content => "<r:children:each><r:snippet name='recursive' /></r:children:each><r:title />"
10
+ create_snippet "yielding", :content => "Before...<r:yield/>...and after"
11
+ create_snippet "div_wrap", :content => "<div><r:yield/></div>"
12
+ create_snippet "nested_yields", :content => '<snippet name="div_wrap">above <r:yield/> below</snippet>'
13
+ create_snippet "yielding_often", :content => '<r:yield/> is <r:yield/>er than <r:yield/>'
14
+ end
15
+
16
+ helpers do
17
+ def create_snippet(name, attributes={})
18
+ create_record :snippet, name.symbolize, snippet_params(attributes.reverse_merge(:name => name))
19
+ end
20
+
21
+ def snippet_params(attributes={})
22
+ name = attributes[:name] || unique_snippet_name
23
+ {
24
+ :name => name,
25
+ :content => "<r:content />"
26
+ }.merge(attributes)
27
+ end
28
+
29
+ private
30
+
31
+ def unique_snippet_name
32
+ @@unique_snippet_name_call_count ||= 0
33
+ @@unique_snippet_name_call_count += 1
34
+ "snippet-#{@@unique_snippet_name_call_count}"
35
+ end
36
+ end
37
+
38
+ end
@@ -0,0 +1,33 @@
1
+ require File.dirname(__FILE__) + "/../../spec_helper"
2
+
3
+ describe Radiant::AdminUI do
4
+ let(:admin) do
5
+ @admin = Radiant::AdminUI.new
6
+ @admin.snippet = @admin.load_default_snippet_regions
7
+ @admin
8
+ end
9
+
10
+ subject{ admin }
11
+ its(:snippet){ should_not be_nil }
12
+ its(:snippets){ should_not be_nil }
13
+
14
+ context 'edit Region' do
15
+ subject{ admin.snippet.edit }
16
+ its(:main){ should == %w{ edit_header edit_form } }
17
+ its(:form){ should == %w{ edit_title edit_content edit_filter } }
18
+ its(:form_bottom){ should == %w{ edit_buttons edit_timestamp } }
19
+ end
20
+
21
+ context 'new Region' do
22
+ subject{ admin.snippet.new }
23
+ its(:main){ should == %w{ edit_header edit_form } }
24
+ its(:form){ should == %w{ edit_title edit_content edit_filter } }
25
+ its(:form_bottom){ should == %w{ edit_buttons edit_timestamp } }
26
+ end
27
+
28
+ subject{ admin.snippet.index }
29
+ its(:top){ should == [] }
30
+ its(:thead){ should == %w{ title_header actions_header } }
31
+ its(:tbody){ should == %w{ title_cell actions_cell } }
32
+ its(:bottom){ should == %w{ new_button } }
33
+ end
@@ -0,0 +1,80 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe "Page rendering snippets" do
4
+ dataset :pages, :snippets
5
+
6
+ test_helper :render
7
+
8
+ let(:page){ pages(:home) }
9
+
10
+ it 'should render a snippet' do
11
+ page.render_snippet(snippets(:first)).should == 'test'
12
+ end
13
+
14
+ it 'should render a snippet with a filter' do
15
+ page.render_snippet(snippets(:markdown)).should match(%r{<p><strong>markdown</strong></p>})
16
+ end
17
+
18
+ it 'should render a snippet with a tag' do
19
+ page.render_snippet(snippets(:radius)).should == 'Home'
20
+ end
21
+
22
+ describe "<r:snippet>" do
23
+ it "should render the contents of the specified snippet" do
24
+ page.should render('<r:snippet name="first" />').as('test')
25
+ end
26
+
27
+ it "should render an error when the snippet does not exist" do
28
+ page.should render('<r:snippet name="non-existant" />').with_error("snippet 'non-existant' not found")
29
+ end
30
+
31
+ it "should render an error when not given a 'name' attribute" do
32
+ page.should render('<r:snippet />').with_error("`snippet' tag must contain a `name' attribute.")
33
+ end
34
+
35
+ it "should filter the snippet with its assigned filter" do
36
+ page.should render('<r:page><r:snippet name="markdown" /></r:page>').matching(%r{<p><strong>markdown</strong></p>})
37
+ end
38
+
39
+ it "should maintain the global page inside the snippet" do
40
+ pages(:parent).should render('<r:snippet name="global_page_cascade" />').as("#{page.title} " * page.children.count)
41
+ end
42
+
43
+ it "should maintain the global page when the snippet renders recursively" do
44
+ pages(:child).should render('<r:snippet name="recursive" />').as("Great GrandchildGrandchildChild")
45
+ end
46
+
47
+ it "should render the specified snippet when called as an empty double-tag" do
48
+ page.should render('<r:snippet name="first"></r:snippet>').as('test')
49
+ end
50
+
51
+ it "should capture contents of a double tag, substituting for <r:yield/> in snippet" do
52
+ page.should render('<r:snippet name="yielding">inner</r:snippet>').
53
+ as('Before...inner...and after')
54
+ end
55
+
56
+ it "should do nothing with contents of double tag when snippet doesn't yield" do
57
+ page.should render('<r:snippet name="first">content disappears!</r:snippet>').
58
+ as('test')
59
+ end
60
+
61
+ it "should render nested yielding snippets" do
62
+ page.should render('<r:snippet name="div_wrap"><r:snippet name="yielding">Hello, World!</r:snippet></r:snippet>').
63
+ as('<div>Before...Hello, World!...and after</div>')
64
+ end
65
+
66
+ it "should render double-tag snippets called from within a snippet" do
67
+ page.should render('<r:snippet name="nested_yields">the content</r:snippet>').
68
+ as('<snippet name="div_wrap">above the content below</snippet>')
69
+ end
70
+
71
+ it "should render contents each time yield is called" do
72
+ page.should render('<r:snippet name="yielding_often">French</r:snippet>').
73
+ as('French is Frencher than French')
74
+ end
75
+ end
76
+
77
+ it "should do nothing when called from page body" do
78
+ page.should render('<r:yield/>').as("")
79
+ end
80
+ end
@@ -0,0 +1,59 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Snippet do
4
+ dataset :snippets
5
+ test_helper :validations
6
+
7
+ before :each do
8
+ @original_filter = Radiant::Config['defaults.snippet.filter']
9
+ @snippet = @model = Snippet.new(snippet_params)
10
+ end
11
+
12
+ after :each do
13
+ Radiant::Config['defaults.snippet.filter'] = @original_filter
14
+ end
15
+
16
+ it "should take the filter from the default filter" do
17
+ Radiant::Config['defaults.snippet.filter'] = "Textile"
18
+ snippet = Snippet.new :name => 'new-snippet'
19
+ snippet.filter_id.should == "Textile"
20
+ end
21
+
22
+ it "shouldn't override existing snippets filters with the default filter" do
23
+ snippet = Snippet.find(:first, :conditions => {:filter_id => nil})
24
+ Radiant::Config['defaults.snippet.filter'] = "Textile"
25
+ snippet.reload
26
+ snippet.filter_id.should_not == "Textile"
27
+ end
28
+
29
+ it 'should validate length of' do
30
+ {
31
+ :name => 100,
32
+ :filter_id => 25
33
+ }.each do |field, max|
34
+ assert_invalid field, ('this must not be longer than %d characters' % max), 'x' * (max + 1)
35
+ assert_valid field, 'x' * max
36
+ end
37
+ end
38
+
39
+ it 'should validate presence of' do
40
+ [:name].each do |field|
41
+ assert_invalid field, 'this must not be blank', '', ' ', nil
42
+ end
43
+ end
44
+
45
+ it 'should validate uniqueness of' do
46
+ assert_invalid :name, 'this name is already in use', 'first', 'another', 'markdown'
47
+ assert_valid :name, 'just-a-test'
48
+ end
49
+
50
+ it 'should validate format of name' do
51
+ assert_valid :name, 'abc', 'abcd-efg', 'abcd_efg', 'abc.html', '/', '123'
52
+ assert_invalid :name, 'cannot contain spaces or tabs'
53
+ end
54
+
55
+ it 'should allow the filter to be specified' do
56
+ @snippet = snippets(:markdown)
57
+ @snippet.filter.should be_kind_of(MarkdownFilter)
58
+ end
59
+ end
@@ -0,0 +1,28 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe UserActionObserver do
4
+ dataset :users, :pages_with_layouts, :snippets
5
+
6
+ before(:each) do
7
+ @user = users(:existing)
8
+ UserActionObserver.current_user = @user
9
+ end
10
+
11
+ it 'should observe create' do
12
+ [
13
+ Snippet.create!(snippet_params)
14
+ ].each do |model|
15
+ model.created_by.should == @user
16
+ end
17
+ end
18
+
19
+ it 'should observe update' do
20
+ [
21
+ snippets(:first)
22
+ ].each do |model|
23
+ model.attributes = model.attributes.dup
24
+ model.save.should == true
25
+ model.updated_by.should == @user
26
+ end
27
+ end
28
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,6 @@
1
+ --colour
2
+ --format
3
+ progress
4
+ --loadby
5
+ mtime
6
+ --reverse
@@ -0,0 +1,36 @@
1
+ unless defined? RADIANT_ROOT
2
+ ENV["RAILS_ENV"] = "test"
3
+ case
4
+ when ENV["RADIANT_ENV_FILE"]
5
+ require ENV["RADIANT_ENV_FILE"]
6
+ when File.dirname(__FILE__) =~ %r{vendor/radiant/vendor/extensions}
7
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../../../")}/config/environment"
8
+ else
9
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../")}/config/environment"
10
+ end
11
+ end
12
+ require "#{RADIANT_ROOT}/spec/spec_helper"
13
+
14
+ Dataset::Resolver.default << (File.dirname(__FILE__) + "/datasets")
15
+
16
+ if File.directory?(File.dirname(__FILE__) + "/matchers")
17
+ Dir[File.dirname(__FILE__) + "/matchers/*.rb"].each {|file| require file }
18
+ end
19
+
20
+ Spec::Runner.configure do |config|
21
+ # config.use_transactional_fixtures = true
22
+ # config.use_instantiated_fixtures = false
23
+ # config.fixture_path = RAILS_ROOT + '/spec/fixtures'
24
+
25
+ # You can declare fixtures for each behaviour like this:
26
+ # describe "...." do
27
+ # fixtures :table_a, :table_b
28
+ #
29
+ # Alternatively, if you prefer to declare them only once, you can
30
+ # do so here, like so ...
31
+ #
32
+ # config.global_fixtures = :table_a, :table_b
33
+ #
34
+ # If you declare global fixtures, be aware that they will be declared
35
+ # for all of your examples, even those that don't use them.
36
+ end
metadata ADDED
@@ -0,0 +1,104 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: radiant-snippets-extension
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 1.0.0
6
+ platform: ruby
7
+ authors:
8
+ - Jim Gay
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2012-03-05 00:00:00 Z
14
+ dependencies: []
15
+
16
+ description: Makes Radiant better by adding snippets!
17
+ email:
18
+ - radiant@radiantcms.org
19
+ executables: []
20
+
21
+ extensions: []
22
+
23
+ extra_rdoc_files: []
24
+
25
+ files:
26
+ - cucumber.yml
27
+ - radiant-snippets-extension.gemspec
28
+ - Rakefile
29
+ - README.md
30
+ - snippets_extension.rb
31
+ - app/controllers/admin/snippets_controller.rb
32
+ - app/helpers/admin/snippets_helper.rb
33
+ - app/models/snippet.rb
34
+ - app/views/admin/snippets/_form.html.haml
35
+ - app/views/admin/snippets/edit.html.haml
36
+ - app/views/admin/snippets/index.html.haml
37
+ - app/views/admin/snippets/new.html.haml
38
+ - app/views/admin/snippets/remove.html.haml
39
+ - config/routes.rb
40
+ - config/initializers/radiant_config.rb
41
+ - config/locales/en.yml
42
+ - features/admin/configuration.feature
43
+ - features/admin/pagination.feature
44
+ - features/admin/snippets_management.feature
45
+ - features/step_definitions/admin/snippet_steps.rb
46
+ - features/support/env.rb
47
+ - features/support/paths.rb
48
+ - lib/radiant-snippets-extension.rb
49
+ - lib/snippet_tags.rb
50
+ - lib/tasks/snippets_extension_tasks.rake
51
+ - spec/spec.opts
52
+ - spec/spec_helper.rb
53
+ - spec/ci/before_script
54
+ - spec/ci/script
55
+ - spec/controllers/admin/snippets_controller_spec.rb
56
+ - spec/datasets/snippets_dataset.rb
57
+ - spec/lib/radiant/admin_ui_spec.rb
58
+ - spec/models/page_spec.rb
59
+ - spec/models/snippet_spec.rb
60
+ - spec/models/user_action_observer_spec.rb
61
+ homepage: http://github.com/radiant
62
+ licenses: []
63
+
64
+ post_install_message:
65
+ rdoc_options: []
66
+
67
+ require_paths:
68
+ - lib
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: "0"
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: "0"
81
+ requirements: []
82
+
83
+ rubyforge_project:
84
+ rubygems_version: 1.8.9
85
+ signing_key:
86
+ specification_version: 3
87
+ summary: Snippets for Radiant CMS
88
+ test_files:
89
+ - spec/spec.opts
90
+ - spec/spec_helper.rb
91
+ - spec/ci/before_script
92
+ - spec/ci/script
93
+ - spec/controllers/admin/snippets_controller_spec.rb
94
+ - spec/datasets/snippets_dataset.rb
95
+ - spec/lib/radiant/admin_ui_spec.rb
96
+ - spec/models/page_spec.rb
97
+ - spec/models/snippet_spec.rb
98
+ - spec/models/user_action_observer_spec.rb
99
+ - features/admin/configuration.feature
100
+ - features/admin/pagination.feature
101
+ - features/admin/snippets_management.feature
102
+ - features/step_definitions/admin/snippet_steps.rb
103
+ - features/support/env.rb
104
+ - features/support/paths.rb