nesta 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +11 -11
  3. data/.hound.yml +2 -0
  4. data/.travis.yml +2 -1
  5. data/CHANGES +43 -0
  6. data/Gemfile +1 -1
  7. data/Gemfile.lock +18 -23
  8. data/lib/nesta/app.rb +0 -5
  9. data/lib/nesta/commands.rb +5 -288
  10. data/lib/nesta/commands/command.rb +58 -0
  11. data/lib/nesta/commands/demo.rb +1 -0
  12. data/lib/nesta/commands/demo/content.rb +38 -0
  13. data/lib/nesta/commands/edit.rb +21 -0
  14. data/lib/nesta/commands/new.rb +57 -0
  15. data/lib/nesta/commands/plugin.rb +1 -0
  16. data/lib/nesta/commands/plugin/create.rb +82 -0
  17. data/lib/nesta/commands/theme.rb +3 -0
  18. data/lib/nesta/commands/theme/create.rb +36 -0
  19. data/lib/nesta/commands/theme/enable.rb +22 -0
  20. data/lib/nesta/commands/theme/install.rb +29 -0
  21. data/lib/nesta/config.rb +1 -6
  22. data/lib/nesta/models.rb +18 -20
  23. data/lib/nesta/version.rb +1 -1
  24. data/nesta.gemspec +1 -0
  25. data/smoke-test.sh +24 -19
  26. data/spec/commands/demo/content_spec.rb +65 -0
  27. data/spec/commands/edit_spec.rb +27 -0
  28. data/spec/commands/new_spec.rb +88 -0
  29. data/spec/commands/plugin/create_spec.rb +97 -0
  30. data/spec/commands/system_spec.rb +25 -0
  31. data/spec/commands/theme/create_spec.rb +41 -0
  32. data/spec/commands/theme/enable_spec.rb +44 -0
  33. data/spec/commands/theme/install_spec.rb +56 -0
  34. data/spec/config_spec.rb +3 -3
  35. data/spec/models_spec.rb +43 -25
  36. data/spec/page_spec.rb +18 -2
  37. data/spec/spec_helper.rb +23 -0
  38. data/templates/Gemfile +1 -1
  39. data/templates/plugins/Gemfile +4 -0
  40. data/templates/plugins/README.md +13 -0
  41. data/templates/plugins/Rakefile +58 -0
  42. data/templates/plugins/gitignore +3 -0
  43. data/templates/plugins/lib/init.rb +13 -0
  44. data/templates/plugins/lib/required.rb +3 -0
  45. data/templates/plugins/lib/version.rb +5 -0
  46. data/templates/plugins/plugin.gemspec +28 -0
  47. data/views/analytics.haml +9 -10
  48. data/views/master.sass +1 -1
  49. metadata +53 -5
  50. data/spec/commands_spec.rb +0 -395
@@ -0,0 +1,58 @@
1
+ module Nesta
2
+ module Commands
3
+ class UsageError < RuntimeError; end
4
+
5
+ module Command
6
+ def run_process(*args)
7
+ system(*args)
8
+ if ! $?.success?
9
+ message = if $?.exitstatus == 127
10
+ "#{args[0]} not found"
11
+ else
12
+ "'#{args.join(' ')}' failed with status #{$?.exitstatus}"
13
+ end
14
+ $stderr.puts "Error: #{message}"
15
+ exit 1
16
+ end
17
+ end
18
+
19
+ def fail(message)
20
+ $stderr.puts "Error: #{message}"
21
+ exit 1
22
+ end
23
+
24
+ def template_root
25
+ File.expand_path('../../../templates', File.dirname(__FILE__))
26
+ end
27
+
28
+ def copy_template(src, dest)
29
+ FileUtils.mkdir_p(File.dirname(dest))
30
+ template = ERB.new(File.read(File.join(template_root, src)), nil, "-")
31
+ File.open(dest, 'w') { |file| file.puts template.result(binding) }
32
+ end
33
+
34
+ def copy_templates(templates)
35
+ templates.each { |src, dest| copy_template(src, dest) }
36
+ end
37
+
38
+ def update_config_yaml(pattern, replacement)
39
+ configured = false
40
+ File.open(Nesta::Config.yaml_path, 'r+') do |file|
41
+ output = ''
42
+ file.each_line do |line|
43
+ if configured
44
+ output << line
45
+ else
46
+ output << line.sub(pattern, replacement)
47
+ configured = true if line =~ pattern
48
+ end
49
+ end
50
+ output << "#{replacement}\n" unless configured
51
+ file.pos = 0
52
+ file.print(output)
53
+ file.truncate(file.pos)
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1 @@
1
+ require File.expand_path('demo/content', File.dirname(__FILE__))
@@ -0,0 +1,38 @@
1
+ require File.expand_path('../command', File.dirname(__FILE__))
2
+
3
+ module Nesta
4
+ module Commands
5
+ module Demo
6
+ class Content
7
+ include Command
8
+
9
+ def initialize(*args)
10
+ @dir = 'content-demo'
11
+ end
12
+
13
+ def clone_or_update_repository
14
+ repository = 'git://github.com/gma/nesta-demo-content.git'
15
+ path = Nesta::Path.local(@dir)
16
+ if File.exist?(path)
17
+ FileUtils.cd(path) { run_process('git', 'pull', 'origin', 'master') }
18
+ else
19
+ run_process('git', 'clone', repository, path)
20
+ end
21
+ end
22
+
23
+ def configure_git_to_ignore_repo
24
+ excludes = Nesta::Path.local('.git/info/exclude')
25
+ if File.exist?(excludes) && File.read(excludes).scan(@dir).empty?
26
+ File.open(excludes, 'a') { |file| file.puts @dir }
27
+ end
28
+ end
29
+
30
+ def execute
31
+ clone_or_update_repository
32
+ configure_git_to_ignore_repo
33
+ update_config_yaml(/^\s*#?\s*content:.*/, "content: #{@dir}")
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,21 @@
1
+ require File.expand_path('command', File.dirname(__FILE__))
2
+
3
+ module Nesta
4
+ module Commands
5
+ class Edit
6
+ include Command
7
+
8
+ def initialize(*args)
9
+ @filename = Nesta::Config.page_path(args.shift)
10
+ end
11
+
12
+ def execute
13
+ editor = ENV.fetch('EDITOR')
14
+ rescue IndexError
15
+ $stderr.puts "No editor: set EDITOR environment variable"
16
+ else
17
+ run_process(editor, @filename)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,57 @@
1
+ require File.expand_path('command', File.dirname(__FILE__))
2
+
3
+ module Nesta
4
+ module Commands
5
+ class New
6
+ include Command
7
+
8
+ def initialize(*args)
9
+ path = args.shift
10
+ options = args.shift || {}
11
+ path.nil? && (raise UsageError.new('path not specified'))
12
+ if File.exist?(path)
13
+ raise RuntimeError.new("#{path} already exists")
14
+ end
15
+ @path = path
16
+ @options = options
17
+ end
18
+
19
+ def make_directories
20
+ %w[content/attachments content/pages].each do |dir|
21
+ FileUtils.mkdir_p(File.join(@path, dir))
22
+ end
23
+ end
24
+
25
+ def have_rake_tasks?
26
+ @options['vlad']
27
+ end
28
+
29
+ def create_repository
30
+ FileUtils.cd(@path) do
31
+ File.open('.gitignore', 'w') do |file|
32
+ file.puts %w[._* .*.swp .bundle .DS_Store .sass-cache].join("\n")
33
+ end
34
+ run_process('git', 'init')
35
+ run_process('git', 'add', '.')
36
+ run_process('git', 'commit', '-m', 'Initial commit')
37
+ end
38
+ end
39
+
40
+ def execute
41
+ make_directories
42
+ templates = {
43
+ 'config.ru' => "#{@path}/config.ru",
44
+ 'config/config.yml' => "#{@path}/config/config.yml",
45
+ 'index.haml' => "#{@path}/content/pages/index.haml",
46
+ 'Gemfile' => "#{@path}/Gemfile"
47
+ }
48
+ templates['Rakefile'] = "#{@path}/Rakefile" if have_rake_tasks?
49
+ if @options['vlad']
50
+ templates['config/deploy.rb'] = "#{@path}/config/deploy.rb"
51
+ end
52
+ copy_templates(templates)
53
+ create_repository if @options['git']
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1 @@
1
+ require File.expand_path('plugin/create', File.dirname(__FILE__))
@@ -0,0 +1,82 @@
1
+ require File.expand_path('../command', File.dirname(__FILE__))
2
+
3
+ module Nesta
4
+ module Commands
5
+ module Plugin
6
+ class Create
7
+ include Command
8
+
9
+ def initialize(*args)
10
+ name = args.shift
11
+ name.nil? && (raise UsageError.new('name not specified'))
12
+ @name = name
13
+ @gem_name = "nesta-plugin-#{name}"
14
+ if File.exist?(@gem_name)
15
+ raise RuntimeError.new("#{@gem_name} already exists")
16
+ end
17
+ end
18
+
19
+ def lib_path(*parts)
20
+ File.join(@gem_name, 'lib', *parts)
21
+ end
22
+
23
+ def module_name
24
+ module_names.join('::')
25
+ end
26
+
27
+ def nested_module_definition_with_version
28
+ indent_level = 2
29
+ indent_with = ' '
30
+
31
+ lines = module_names.map { |name| "module #{name}\n" }
32
+ indent_levels = 0.upto(module_names.size - 1).to_a
33
+
34
+ lines << "VERSION = '0.1.0'\n"
35
+ indent_levels << module_names.size
36
+
37
+ (module_names.size - 1).downto(0).each do |indent_level|
38
+ lines << "end\n"
39
+ indent_levels << indent_level
40
+ end
41
+
42
+ ''.tap do |code|
43
+ lines.each_with_index do |line, i|
44
+ code << ' ' * (indent_levels[i] + 2) + line
45
+ end
46
+ end
47
+ end
48
+
49
+ def make_directories
50
+ FileUtils.mkdir_p(File.join(@gem_name, 'lib', @gem_name))
51
+ end
52
+
53
+ def gem_path(path)
54
+ File.join(@gem_name, path)
55
+ end
56
+
57
+ def execute
58
+ make_directories
59
+ copy_templates(
60
+ 'plugins/README.md' => gem_path('README.md'),
61
+ 'plugins/gitignore' => gem_path('.gitignore'),
62
+ 'plugins/plugin.gemspec' => gem_path("#{@gem_name}.gemspec"),
63
+ 'plugins/Gemfile' => gem_path('Gemfile'),
64
+ 'plugins/lib/required.rb' => gem_path("lib/#{@gem_name}.rb"),
65
+ 'plugins/lib/version.rb' => gem_path("lib/#{@gem_name}/version.rb"),
66
+ 'plugins/lib/init.rb' => gem_path("lib/#{@gem_name}/init.rb"),
67
+ 'plugins/Rakefile' => gem_path('Rakefile')
68
+ )
69
+ Dir.chdir(@gem_name) do
70
+ run_process('git', 'init')
71
+ run_process('git', 'add', '.')
72
+ end
73
+ end
74
+
75
+ private
76
+ def module_names
77
+ @name.split('-').map { |name| name.capitalize }
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,3 @@
1
+ require File.expand_path('theme/create', File.dirname(__FILE__))
2
+ require File.expand_path('theme/enable', File.dirname(__FILE__))
3
+ require File.expand_path('theme/install', File.dirname(__FILE__))
@@ -0,0 +1,36 @@
1
+ require File.expand_path('../command', File.dirname(__FILE__))
2
+
3
+ module Nesta
4
+ module Commands
5
+ module Theme
6
+ class Create
7
+ include Command
8
+
9
+ def initialize(*args)
10
+ name = args.shift
11
+ options = args.shift || {}
12
+ name.nil? && (raise UsageError.new('name not specified'))
13
+ @name = name
14
+ @theme_path = Nesta::Path.themes(@name)
15
+ fail("#{@theme_path} already exists") if File.exist?(@theme_path)
16
+ end
17
+
18
+ def make_directories
19
+ FileUtils.mkdir_p(File.join(@theme_path, 'public', @name))
20
+ FileUtils.mkdir_p(File.join(@theme_path, 'views'))
21
+ end
22
+
23
+ def execute
24
+ make_directories
25
+ copy_templates(
26
+ 'themes/README.md' => "#{@theme_path}/README.md",
27
+ 'themes/app.rb' => "#{@theme_path}/app.rb",
28
+ 'themes/views/layout.haml' => "#{@theme_path}/views/layout.haml",
29
+ 'themes/views/page.haml' => "#{@theme_path}/views/page.haml",
30
+ 'themes/views/master.sass' => "#{@theme_path}/views/master.sass"
31
+ )
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,22 @@
1
+ require File.expand_path('../command', File.dirname(__FILE__))
2
+
3
+ module Nesta
4
+ module Commands
5
+ module Theme
6
+ class Enable
7
+ include Command
8
+
9
+ def initialize(*args)
10
+ name = args.shift
11
+ options = args.shift || {}
12
+ name.nil? && (raise UsageError.new('name not specified'))
13
+ @name = name
14
+ end
15
+
16
+ def execute
17
+ update_config_yaml(/^\s*#?\s*theme:.*/, "theme: #{@name}")
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,29 @@
1
+ require File.expand_path('../command', File.dirname(__FILE__))
2
+
3
+ module Nesta
4
+ module Commands
5
+ module Theme
6
+ class Install
7
+ include Command
8
+
9
+ def initialize(*args)
10
+ url = args.shift
11
+ options = args.shift || {}
12
+ url.nil? && (raise UsageError.new('URL not specified'))
13
+ @url = url
14
+ @name = File.basename(url, '.git').sub(/nesta-theme-/, '')
15
+ end
16
+
17
+ def execute
18
+ run_process('git', 'clone', @url, "themes/#{@name}")
19
+ FileUtils.rm_r(File.join("themes/#{@name}", '.git'))
20
+ enable
21
+ end
22
+
23
+ def enable
24
+ Enable.new(@name).execute
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -90,18 +90,13 @@ module Nesta
90
90
  end
91
91
  private_class_method :yaml_exists?
92
92
 
93
- def self.can_use_yaml?
94
- ENV.keys.grep(/^NESTA/).empty? && yaml_exists?
95
- end
96
- private_class_method :can_use_yaml?
97
-
98
93
  def self.from_hash(hash, setting)
99
94
  hash.fetch(setting) { raise NotDefined.new(setting) }
100
95
  end
101
96
  private_class_method :from_hash
102
97
 
103
98
  def self.from_yaml(setting)
104
- raise NotDefined.new(setting) unless can_use_yaml?
99
+ raise NotDefined.new(setting) unless yaml_exists?
105
100
  self.yaml_conf ||= YAML::load(ERB.new(IO.read(yaml_path)).result)
106
101
  env_config = self.yaml_conf.fetch(Nesta::App.environment.to_s, {})
107
102
  begin
@@ -1,10 +1,10 @@
1
1
  require 'time'
2
2
 
3
- Tilt.register Tilt::MarukuTemplate, 'mdown'
4
- Tilt.register Tilt::KramdownTemplate, 'mdown'
5
- Tilt.register Tilt::BlueClothTemplate, 'mdown'
6
- Tilt.register Tilt::RDiscountTemplate, 'mdown'
7
- Tilt.register Tilt::RedcarpetTemplate, 'mdown'
3
+ Tilt.register Tilt::MarukuTemplate, 'mdown', 'md'
4
+ Tilt.register Tilt::KramdownTemplate, 'mdown', 'md'
5
+ Tilt.register Tilt::BlueClothTemplate, 'mdown', 'md'
6
+ Tilt.register Tilt::RDiscountTemplate, 'mdown', 'md'
7
+ Tilt.register Tilt::RedcarpetTemplate, 'mdown', 'md'
8
8
 
9
9
  module Nesta
10
10
  class HeadingNotSet < RuntimeError; end
@@ -12,7 +12,7 @@ module Nesta
12
12
  class MetadataParseError < RuntimeError; end
13
13
 
14
14
  class FileModel
15
- FORMATS = [:mdown, :haml, :textile]
15
+ FORMATS = [:mdown, :md, :haml, :textile]
16
16
  @@page_cache = {}
17
17
  @@filename_cache = {}
18
18
 
@@ -113,7 +113,7 @@ module Nesta
113
113
  (metadata('template') || 'page').to_sym
114
114
  end
115
115
 
116
- def to_html(scope = nil)
116
+ def to_html(scope = Object.new)
117
117
  convert_to_html(@format, scope, markup)
118
118
  end
119
119
 
@@ -128,7 +128,7 @@ module Nesta
128
128
  def keywords
129
129
  metadata('keywords')
130
130
  end
131
-
131
+
132
132
  def metadata(key)
133
133
  @metadata[key]
134
134
  end
@@ -220,7 +220,7 @@ module Nesta
220
220
 
221
221
  def heading
222
222
  regex = case @format
223
- when :mdown
223
+ when :mdown, :md
224
224
  /^#\s*(.*?)(\s*#+|$)/
225
225
  when :haml
226
226
  /^\s*%h1\s+(.*)/
@@ -236,7 +236,7 @@ module Nesta
236
236
  rescue HeadingNotSet
237
237
  raise LinkTextNotSet, "Need to link to '#{abspath}' but can't get link text"
238
238
  end
239
-
239
+
240
240
  def title
241
241
  metadata('title') || link_text
242
242
  rescue LinkTextNotSet
@@ -265,13 +265,13 @@ module Nesta
265
265
  def summary
266
266
  if summary_text = metadata("summary")
267
267
  summary_text.gsub!('\n', "\n")
268
- convert_to_html(@format, nil, summary_text)
268
+ convert_to_html(@format, Object.new, summary_text)
269
269
  end
270
270
  end
271
271
 
272
272
  def body_markup
273
273
  case @format
274
- when :mdown
274
+ when :mdown, :md
275
275
  markup.sub(/^#[^#].*$\r?\n(\r?\n)?/, '')
276
276
  when :haml
277
277
  markup.sub(/^\s*%h1\s+.*$\r?\n(\r?\n)?/, '')
@@ -280,23 +280,20 @@ module Nesta
280
280
  end
281
281
  end
282
282
 
283
- def body(scope = nil)
283
+ def body(scope = Object.new)
284
284
  convert_to_html(@format, scope, body_markup)
285
285
  end
286
286
 
287
287
  def categories
288
288
  paths = category_strings.map { |specifier| specifier.sub(/:-?\d+$/, '') }
289
- pages = valid_paths(paths).map { |p| Page.find_by_path(p) }
290
- pages.sort do |x, y|
291
- x.link_text.downcase <=> y.link_text.downcase
292
- end
289
+ valid_paths(paths).map { |p| Page.find_by_path(p) }
293
290
  end
294
291
 
295
292
  def priority(category)
296
293
  category_string = category_strings.detect do |string|
297
294
  string =~ /^#{category}([,:\s]|$)/
298
295
  end
299
- category_string && category_string.split(':', 2)[-1].to_i
296
+ category_string && category_string.split(':', 2)[-1].to_i
300
297
  end
301
298
 
302
299
  def parent
@@ -309,6 +306,7 @@ module Nesta
309
306
  return parent unless parent.nil?
310
307
  parent_path = File.dirname(parent_path)
311
308
  end
309
+ return categories.first unless categories.empty?
312
310
  Page.load('index')
313
311
  end
314
312
  end
@@ -384,15 +382,15 @@ module Nesta
384
382
  rescue EOFError
385
383
  else
386
384
  page = Page.load(path.strip)
385
+ current_depth = path.scan(INDENT).size
387
386
  if page
388
- current_depth = path.scan(INDENT).size
389
387
  if current_depth > depth
390
388
  sub_menu_for_depth(menu, depth) << [page]
391
389
  else
392
390
  sub_menu_for_depth(menu, current_depth) << page
393
391
  end
394
- append_menu_item(menu, file, current_depth)
395
392
  end
393
+ append_menu_item(menu, file, current_depth)
396
394
  end
397
395
 
398
396
  def self.sub_menu_for_depth(menu, depth)