aladdin 0.0.4 → 0.0.5

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 (43) hide show
  1. data/assets/fonts/general_foundicons.eot +0 -0
  2. data/assets/fonts/general_foundicons.svg +15 -0
  3. data/assets/fonts/general_foundicons.ttf +0 -0
  4. data/assets/fonts/general_foundicons.woff +0 -0
  5. data/bin/aladdin +3 -2
  6. data/lib/aladdin.rb +14 -69
  7. data/lib/aladdin/app.rb +5 -1
  8. data/lib/aladdin/commands.rb +48 -0
  9. data/lib/aladdin/commands/new.rb +59 -9
  10. data/lib/aladdin/commands/server.rb +33 -5
  11. data/lib/aladdin/config.rb +52 -0
  12. data/lib/aladdin/constants.rb +29 -0
  13. data/lib/aladdin/render.rb +8 -0
  14. data/lib/aladdin/render/error.rb +3 -6
  15. data/lib/aladdin/render/markdown.rb +16 -25
  16. data/lib/aladdin/render/templates.rb +2 -0
  17. data/lib/aladdin/render/templates/header.rb +52 -0
  18. data/lib/aladdin/render/{image.rb → templates/image.rb} +0 -0
  19. data/lib/aladdin/render/{multi.rb → templates/multi.rb} +0 -0
  20. data/lib/aladdin/render/{navigation.rb → templates/navigation.rb} +5 -5
  21. data/lib/aladdin/render/{problem.rb → templates/problem.rb} +1 -1
  22. data/lib/aladdin/render/{short.rb → templates/short.rb} +0 -0
  23. data/lib/aladdin/render/{table.rb → templates/table.rb} +0 -0
  24. data/lib/aladdin/render/{template.rb → templates/template.rb} +5 -3
  25. data/lib/aladdin/submission.rb +3 -3
  26. data/lib/aladdin/support.rb +10 -0
  27. data/lib/aladdin/support/core_ext.rb +2 -0
  28. data/lib/aladdin/support/core_ext/hash.rb +10 -0
  29. data/lib/aladdin/support/logger.rb +29 -0
  30. data/lib/aladdin/{mixin → support}/weak_comparator.rb +8 -6
  31. data/lib/aladdin/version.rb +1 -1
  32. data/skeleton/gitignore +3 -0
  33. data/skeleton/manifest.json +9 -0
  34. data/views/haml/header.haml +5 -0
  35. data/views/haml/layout.haml +4 -0
  36. data/views/haml/nav.haml +3 -3
  37. data/views/scss/_settings.scss +30 -1
  38. data/views/scss/app.scss +26 -5
  39. data/views/scss/general_foundicons.scss +71 -0
  40. data/views/scss/general_foundicons_ie7.scss +56 -0
  41. metadata +45 -12
  42. data/lib/aladdin/cli.rb +0 -29
  43. data/lib/aladdin/mixin/logger.rb +0 -26
Binary file
@@ -0,0 +1,15 @@
1
+ <?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd" > <svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">
2
+ <defs >
3
+ <font id="generalfoundicons" horiz-adv-x="955" ><font-face
4
+ font-family="General Foundicons"
5
+ units-per-em="1000"
6
+ panose-1="0 0 0 0 0 0 0 0 0 0"
7
+ ascent="1000"
8
+ descent="0"
9
+ alphabetic="0" />
10
+ <missing-glyph horiz-adv-x="250" />
11
+ <glyph unicode=" " glyph-name="space" horiz-adv-x="250" />
12
+ <glyph unicode="~" glyph-name="asciitilde" horiz-adv-x="1000" />
13
+ </font>
14
+ </defs>
15
+ </svg>
Binary file
data/bin/aladdin CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
+ # ~*~ encoding: utf-8 ~*~
2
3
 
3
4
  $:.unshift File.join File.dirname(__FILE__), *%w(.. lib)
4
-
5
- require 'aladdin/cli'
5
+ require 'aladdin/commands'
6
+ Aladdin::Commands.parse!
data/lib/aladdin.rb CHANGED
@@ -1,88 +1,33 @@
1
1
  # ~*~ encoding: utf-8 ~*~
2
- require 'sinatra'
3
- require 'zurb-foundation'
4
- require 'albino'
5
- require 'haml'
6
- require 'redcarpet'
7
- require 'htmlentities'
8
- require 'sanitize'
9
- require 'yaml'
10
2
  require 'json'
3
+ require 'active_support/core_ext/hash'
11
4
 
12
- require 'aladdin/mixin/logger'
13
- require 'aladdin/mixin/weak_comparator'
14
- require 'aladdin/submission'
15
- require 'aladdin/render/markdown'
5
+ require 'aladdin/constants'
6
+ require 'aladdin/config'
7
+ require 'aladdin/support'
8
+ require 'aladdin/render'
16
9
 
17
- # Aladdin is a gem that tutorial authors can use to preview and test their
18
- # tutorials locally.
10
+ # Aladdin is a gem that lesson authors can use to preview and test their
11
+ # lessons locally.
19
12
  module Aladdin
20
-
21
- # Name of configuration file.
22
- CONFIG_FILE = '.genie.yml'
23
-
24
- # Default configuration options.
25
- DEFAULT_CONFIG = {
26
- 'verify' => {
27
- 'bin' => 'make',
28
- 'arg_prefix' => ''
29
- },
30
- 'title' => 'Lesson X',
31
- 'description' => 'This is a placeholder description. You should provide your own',
32
- 'categories' => []
33
- }
34
-
35
13
  class << self
36
14
 
37
- attr_reader :config, :root
15
+ include Support::Logger
16
+ attr_accessor :config
38
17
 
39
18
  # Launches the tutorial app using 'thin' as the default webserver.
40
19
  # @option opts [String] from path to author's markdown documents;
41
20
  # defaults to the current working directory
42
21
  def launch(opts = {})
43
- @root = opts[:from] || '.'
44
- configure
22
+ root = opts[:from] || Dir.pwd
23
+ @config = Config.new root
24
+ require 'aladdin/app'
45
25
  Aladdin::App.set :views, Aladdin::VIEWS.merge(markdown: root)
46
26
  Aladdin::App.run!
47
- end
48
-
49
- private
50
-
51
- # Reads configuration options from +.genie.yml+ and merges it into
52
- # {DEFAULT_CONFIG}.
53
- def configure
54
- config_file = File.expand_path CONFIG_FILE, root
55
- config = File.exists?(config_file) ? YAML.load_file(config_file) : {}
56
- @config = DEFAULT_CONFIG.merge(config) { |k, l, r|
57
- (l.is_a?(Hash) and r.is_a?(Hash)) ? l.merge(r) : r
58
- }
59
- end
60
-
61
- # Converts a hash to struct.
62
- def to_struct(hash)
63
- Struct.new( *(k = hash.keys) ).new( *hash.values_at( *k ) )
27
+ rescue => e
28
+ logger.error e.message
64
29
  end
65
30
 
66
31
  end
67
-
68
- # Paths to different types of views.
69
- VIEWS = {
70
- haml: File.expand_path('../../views/haml', __FILE__),
71
- scss: File.expand_path('../../views/scss', __FILE__),
72
- default: File.expand_path('../../views', __FILE__)
73
- }
74
-
75
- # Paths to other parts of the library.
76
- PATHS = to_struct(
77
- assets: File.expand_path('../../assets', __FILE__),
78
- ).freeze
79
-
80
- # File extension for solution files.
81
- DATA_EXT = '.sol'
82
-
83
- # @todo TODO allow configuration?
84
- DATA_DIR = Dir.tmpdir
85
-
86
32
  end
87
33
 
88
- require 'aladdin/app'
data/lib/aladdin/app.rb CHANGED
@@ -1,4 +1,8 @@
1
1
  # ~*~ encoding: utf-8 ~*~
2
+ require 'sinatra'
3
+ require 'zurb-foundation'
4
+ require 'aladdin/submission'
5
+
2
6
  module Aladdin
3
7
 
4
8
  # Sinatra app that serves the tutorial. Should be able to use this in a
@@ -94,7 +98,7 @@ module Aladdin
94
98
  get '/*' do |path|
95
99
  path = path.empty? ? INDEX : path.to_sym
96
100
  render_or_pass do
97
- markdown(path, locals: Aladdin.config)
101
+ markdown(path, locals: Aladdin.config.to_hash)
98
102
  end
99
103
  end
100
104
 
@@ -0,0 +1,48 @@
1
+ # ~*~ encoding: utf-8 ~*~
2
+ Signal.trap('INT') { puts; exit(1) }
3
+
4
+ module Aladdin
5
+
6
+ # Parses the command line arguments and invokes the relevant command.
7
+ # @example Adding a command
8
+ # Commands.register do
9
+ # def new
10
+ # # do stuff
11
+ # end
12
+ # end
13
+ module Commands
14
+
15
+ # Path to USAGE file.
16
+ USAGE = File.join File.dirname(__FILE__), *%w(commands/USAGE)
17
+
18
+ # Registers a new command.
19
+ def register(&block)
20
+ extend Module.new(&block)
21
+ end
22
+
23
+ # Parses the command line arguments.
24
+ def parse!(argv=ARGV, opts={})
25
+ command = argv.shift
26
+ case command
27
+ when '--version', '-v'
28
+ puts "Aladdin #{Aladdin::VERSION}"
29
+ exit 0
30
+ when '--help', '-h'
31
+ puts File.read USAGE
32
+ exit 0
33
+ else
34
+ require_relative 'commands/new'
35
+ require_relative 'commands/server'
36
+ send command, argv, opts
37
+ end
38
+ rescue => e
39
+ puts e.message
40
+ puts File.read USAGE
41
+ exit 1
42
+ end
43
+
44
+ extend self
45
+
46
+ end
47
+
48
+ end
@@ -1,16 +1,66 @@
1
1
  # ~*~ encoding: utf-8 ~*~
2
2
  require 'aladdin'
3
3
  require 'optparse'
4
+ require 'aladdin/constants'
4
5
 
5
- # Array of skeleton files to be copied over.
6
- SKELETON_FILES = %w(.genie.yml index.md images)
6
+ module Aladdin
7
7
 
8
- opt_parser = OptionParser.new do |opts|
9
- opts.banner = "Usage: aladdin new [options] [LESSON_PATH]"
10
- end
11
- opt_parser.parse!
8
+ module Commands
9
+
10
+ # @example
11
+ # $> aladdin new path/to/lesson/root
12
+ module New
13
+
14
+ # Array of skeleton files to be copied over.
15
+ FILES = %w(index.md images) << Aladdin::Config::FILE
16
+
17
+ # Array of dot files to be copied over and renamed.
18
+ DOT_FILES = %w(gitignore)
19
+
20
+ # Flags for {FileUtils.cp_r}
21
+ COPY_FLAGS = {verbose: true}
22
+
23
+ # Copies skeleton files to given destination.
24
+ # @param [String] dest destination path
25
+ # @param [Hash] flags options for {FileUtils.cp_r}
26
+ # @return [Void]
27
+ def copy_files(dest, flags={})
28
+ flags = COPY_FLAGS.merge flags
29
+ paths = FILES.map { |file| path_to file }
30
+ FileUtils.cp_r paths, dest, flags
31
+ DOT_FILES.each do |file|
32
+ FileUtils.cp_r path_to(file), File.join(dest, '.' + file), flags
33
+ end
34
+ end
12
35
 
13
- root = ARGV[0] || Dir.pwd
36
+ # Prefixes +filename+ with the skeleton directory.
37
+ # @param [String] filename name of file to resolve
38
+ # @return [String] path
39
+ def path_to(file)
40
+ File.expand_path file, Aladdin::PATHS.skeleton
41
+ end
14
42
 
15
- Dir.chdir File.join File.dirname(__FILE__), *%w(.. .. .. skeleton)
16
- FileUtils.cp_r SKELETON_FILES, root, verbose: true
43
+ # Parses the command line arguments.
44
+ # @param [Array] argv command line arguments
45
+ # @return [Void]
46
+ def parse!(argv)
47
+ opt_parser = OptionParser.new do |opts|
48
+ opts.banner = "Usage: aladdin new [options] [LESSON_PATH]"
49
+ end
50
+ opt_parser.parse! argv
51
+ end
52
+
53
+ extend self
54
+
55
+ Commands.register do
56
+ def new(argv=ARGV, opts={})
57
+ New.parse! argv
58
+ New.copy_files(argv[0] || Dir.pwd, opts)
59
+ end
60
+ end
61
+
62
+ end
63
+
64
+ end
65
+
66
+ end
@@ -2,9 +2,37 @@
2
2
  require 'aladdin'
3
3
  require 'optparse'
4
4
 
5
- opt_parser = OptionParser.new do |opts|
6
- opts.banner = "Usage: aladdin server [options] [LESSON_PATH]"
7
- end
8
- opt_parser.parse!
5
+ module Aladdin
6
+
7
+ module Commands
8
+
9
+ # @example
10
+ # $> aladdin server path/to/lesson/root
11
+ module Server
12
+
13
+ # Parses the command line arguments.
14
+ # @param [Array] argv command line arguments
15
+ # @return [Void]
16
+ def parse!(argv)
17
+ opt_parser = OptionParser.new do |opts|
18
+ opts.banner = "Usage: aladdin server [options] [LESSON_PATH]"
19
+ end
20
+ opt_parser.parse! argv
21
+ end
22
+
23
+ extend self
9
24
 
10
- Aladdin.launch from: ARGV[0]
25
+ Commands.register do
26
+ def server(argv=ARGV, opts={})
27
+ Server.parse! argv
28
+ Aladdin.launch opts.merge(from: argv[0])
29
+ rescue => e
30
+ puts e.message
31
+ end
32
+ end
33
+
34
+ end
35
+
36
+ end
37
+
38
+ end
@@ -0,0 +1,52 @@
1
+ # ~*~ encoding: utf-8 ~*~
2
+
3
+ module Aladdin
4
+
5
+ # Raised when there is a configuration error.
6
+ class ConfigError < StandardError; end
7
+
8
+ # Configuration options for Aladdin.
9
+ class Config
10
+
11
+ # Name of configuration file.
12
+ FILE = 'manifest.json'
13
+
14
+ # Default configuration options.
15
+ DEFAULTS = {
16
+ 'verify' => {
17
+ 'bin' => 'make',
18
+ 'arg_prefix' => ''
19
+ },
20
+ 'title' => 'Lesson X',
21
+ 'description' => 'This is a placeholder description. You should provide your own',
22
+ 'categories' => []
23
+ }
24
+
25
+ # Creates a new configuration from the file at the given path. Merges the
26
+ # configuration hash parsed from the file with {DEFAULTS}. Raises
27
+ # {ConfigError} if the file could not be read or parsed.
28
+ # @param [String] root path to lesson root
29
+ def initialize(root)
30
+ path = File.expand_path FILE, root
31
+ case
32
+ when (not File.exist? path)
33
+ ConfigError.new("We couldn't find a manifest file at #{path}")
34
+ when (not File.readable? path)
35
+ ConfigError.new("We found a manifest file at #{path}, but couldn't " +
36
+ "read it. Please ensure that the permissions are set correctly.")
37
+ else
38
+ config = ::JSON.parse(File.read path)
39
+ @config = DEFAULTS.deep_merge config
40
+ end
41
+ rescue ::JSON::JSONError => e
42
+ raise ConfigError.new e.message
43
+ end
44
+
45
+ # @return [Hash] a hash copy of the configuration options
46
+ def to_hash
47
+ @config.clone
48
+ end
49
+
50
+ end
51
+
52
+ end
@@ -0,0 +1,29 @@
1
+ # ~*~ encoding: utf-8 ~*~
2
+ require 'aladdin/support/core_ext/hash'
3
+
4
+ module Aladdin
5
+
6
+ root = File.expand_path('../../..', __FILE__)
7
+
8
+ # Paths to other parts of the library.
9
+ PATHS = {
10
+ root: root,
11
+ assets: File.expand_path('assets', root),
12
+ skeleton: File.expand_path('skeleton', root)
13
+ }.to_struct.freeze
14
+
15
+ # Paths to different types of views.
16
+ VIEWS = {
17
+ haml: File.expand_path('views/haml', root),
18
+ scss: File.expand_path('views/scss', root),
19
+ default: File.expand_path('views', root)
20
+ }
21
+
22
+ # @todo TODO allow configuration?
23
+ require 'tmpdir'
24
+ DATA_DIR = Dir.tmpdir
25
+
26
+ # File extension for solution files.
27
+ SOLUTION_EXT = '.sol'
28
+
29
+ end
@@ -0,0 +1,8 @@
1
+ # ~*~ encoding: utf-8 ~*~
2
+ require 'albino'
3
+ require 'haml'
4
+ require 'redcarpet'
5
+ require 'htmlentities'
6
+ require 'sanitize'
7
+
8
+ require 'aladdin/render/markdown'
@@ -4,16 +4,13 @@ module Aladdin
4
4
  module Render
5
5
 
6
6
  # The base exception for {Aladdin::Render} Errors
7
- class Error < StandardError
8
- end
7
+ class Error < StandardError; end
9
8
 
10
9
  # This exception is raised if a parse error occurs.
11
- class ParseError < Error
12
- end
10
+ class ParseError < Error; end
13
11
 
14
12
  # This exception is raised if a render error occurs.
15
- class RenderError < Error
16
- end
13
+ class RenderError < Error; end
17
14
 
18
15
  end
19
16
 
@@ -1,17 +1,11 @@
1
+ # ~*~ encoding: utf-8 ~*~
1
2
  require 'aladdin/render/sanitize'
2
3
  require 'aladdin/render/error'
3
- require 'aladdin/render/template'
4
- require 'aladdin/render/image'
5
- require 'aladdin/render/problem'
6
- require 'aladdin/render/multi'
7
- require 'aladdin/render/short'
8
- require 'aladdin/render/table'
9
- require 'aladdin/render/navigation'
4
+ require 'aladdin/render/templates'
10
5
 
11
- # ~*~ encoding: utf-8 ~*~
12
6
  module Aladdin
13
7
 
14
- # aladdin-render module for all of Laddin's rendering needs.
8
+ # aladdin-render module for all of Aladdin's rendering needs.
15
9
  module Render
16
10
 
17
11
  # HTML Renderer for Markdown.
@@ -23,7 +17,7 @@ module Aladdin
23
17
  #
24
18
  # @see http://github.github.com/github-flavored-markdown/
25
19
  class HTML < ::Redcarpet::Render::HTML
26
- include Aladdin::Mixin::Logger
20
+ include Aladdin::Support::Logger
27
21
 
28
22
  @sanitize = Aladdin::Sanitize.new
29
23
  @entities = HTMLEntities.new
@@ -40,7 +34,7 @@ module Aladdin
40
34
  # Renderer configuration options.
41
35
  CONFIGURATION = {
42
36
  hard_wrap: true,
43
- safe_links_only: true,
37
+ no_styles: true,
44
38
  }
45
39
 
46
40
  # Creates a new HTML renderer.
@@ -48,8 +42,9 @@ module Aladdin
48
42
  def initialize(options = {})
49
43
  super options.merge(CONFIGURATION)
50
44
  exe_template = File.join(Aladdin::VIEWS[:haml], 'exe.haml')
51
- @exe, @nav = Haml::Engine.new(File.read exe_template), Navigation.new
52
- @prob, @img = 0, 0 # indices for Problem # and Figure #
45
+ @exe = Haml::Engine.new(File.read exe_template)
46
+ @nav, @headers = Navigation.new, Headers.new
47
+ @prob, @img = 0, 0 # indices for Problem #, Figure #
53
48
  end
54
49
 
55
50
  # Pygmentizes code blocks.
@@ -77,15 +72,10 @@ module Aladdin
77
72
  p(text)
78
73
  end
79
74
 
80
- # Increases all header levels by one and keeps track of document
81
- # sections.
75
+ # Increases all header levels by one and keeps a navigation bar.
82
76
  def header(text, level)
83
- level += 1
84
- html = h(text, level)
85
- if level == 2
86
- index = @nav << text
87
- html += "<a name='section_#{index}' data-magellan-destination='section_#{index}'/>"
88
- end
77
+ html, name = h(text, level += 1)
78
+ @nav.append(text, name) if level == 2
89
79
  html
90
80
  end
91
81
 
@@ -120,14 +110,15 @@ module Aladdin
120
110
  # Prepares a block image. Raises {RenderError} or {ParseError} if the
121
111
  # given text does not contain a valid image block.
122
112
  def block_image(text)
123
- image = Image.parse(text)
124
- image.render(index: @img += 1)
113
+ Image.parse(text).render(index: @img += 1)
125
114
  end
126
115
 
127
116
  # Wraps the given text with header tags.
128
- # @return [String] wrapped text
117
+ # @return [String] rendered HTML
118
+ # @return [String] anchor name
129
119
  def h(text, level)
130
- "<h#{level}>#{text}</h#{level}>"
120
+ header = @headers.add(text, level)
121
+ return header.render, header.name
131
122
  end
132
123
 
133
124
  # Wraps the given text with paragraph tags.
@@ -0,0 +1,2 @@
1
+ base_path = 'aladdin/render/templates/'
2
+ %w(template header image problem multi short table navigation).each { |f| require base_path + f }
@@ -0,0 +1,52 @@
1
+ # ~*~ encoding: utf-8 ~*~
2
+ require 'active_support/core_ext/string/inflections'
3
+
4
+ module Aladdin
5
+
6
+ module Render
7
+
8
+ # Keeps track of headers within the same document. It's responsible for
9
+ # assigning unique names that can be used in the anchors.
10
+ class Headers
11
+
12
+ def initialize
13
+ @headers = {}
14
+ end
15
+
16
+ # Adds a new header to the set.
17
+ # @return [Header] header
18
+ def add(text, level=1)
19
+ name = text.parameterize
20
+ if @headers.include? name
21
+ name += '-%d' % (@headers[name] += 1)
22
+ else @headers[name] = 0 end
23
+ Header.new(text, level, name)
24
+ end
25
+
26
+ end
27
+
28
+ # Renders a header (e.g. +h1+, +h2+, ...) with anchors.
29
+ class Header < Template
30
+
31
+ # Name of template file for rendering headers.
32
+ TEMPLATE = 'header.haml'
33
+
34
+ attr_reader :name
35
+
36
+ # Creates a new header.
37
+ # @param [String] text header text
38
+ # @param [Fixnum] level 1 to 6
39
+ # @param [String] name anchor name
40
+ def initialize(text, level, name)
41
+ @text, @level, @name = text, level, name
42
+ end
43
+
44
+ def render(locals={})
45
+ super locals.merge(text: @text, level: @level, name: @name)
46
+ end
47
+
48
+ end
49
+
50
+ end
51
+
52
+ end
File without changes
File without changes
@@ -11,15 +11,15 @@ module Aladdin
11
11
 
12
12
  # Creates a new navigation bar.
13
13
  def initialize
14
- @sections = []
14
+ @sections = {}
15
15
  end
16
16
 
17
17
  # Adds a new section.
18
18
  # @param [String] heading section heading
19
- # @return [Fixnum] section index
20
- def <<(heading)
21
- @sections << heading
22
- @sections.size - 1
19
+ # @param [String] name anchor name
20
+ # @return [void]
21
+ def append(heading, name)
22
+ @sections[name] = heading
23
23
  end
24
24
 
25
25
  # Renders the navigation bar in HTML.
@@ -78,7 +78,7 @@ module Aladdin
78
78
  # so that the author doesn't have to read the logs.
79
79
  def save!
80
80
  raise RenderError.new('Invalid problem.') unless valid?
81
- solution = File.join(Aladdin::DATA_DIR, id + Aladdin::DATA_EXT)
81
+ solution = File.join(Aladdin::DATA_DIR, id + Aladdin::SOLUTION_EXT)
82
82
  File.open(solution, 'wb+') { |file| Marshal.dump answer, file }
83
83
  end
84
84
 
File without changes
File without changes
@@ -3,13 +3,14 @@ module Aladdin
3
3
 
4
4
  module Render
5
5
 
6
- # Child classes should provide a +TEMPLATE+ string constant that contains
7
- # the path to the HAML file.
6
+ # Base class for all templates. Child classes should provide a +TEMPLATE+
7
+ # string constant that contains the path to the relevant HAML file.
8
8
  class Template
9
9
 
10
10
  # Renders the given problem using {#view}.
11
11
  # @todo TODO should probably show some error message in the preview,
12
12
  # so that the author doesn't have to read the logs.
13
+ # @params [Hash] locals local variables to pass to the template
13
14
  def render(locals={})
14
15
  view.render Object.new, locals
15
16
  end
@@ -17,7 +18,8 @@ module Aladdin
17
18
  private
18
19
 
19
20
  # Retrieves the +view+ singleton. If it is nil, initializes it from
20
- # +self.class.TEMPLATE+.
21
+ # +self.class.TEMPLATE+. Note that this is reloaded with every refresh so
22
+ # I can edit the templates without refreshing.
21
23
  # @return [Haml::Engine] haml engine
22
24
  def view
23
25
  return @view unless @view.nil?
@@ -10,8 +10,8 @@ module Aladdin
10
10
  # it's unsuitable for production use. It does not impose any security
11
11
  # restrictions at all.
12
12
  class Submission
13
- include Aladdin::Mixin::Logger
14
- include Aladdin::Mixin::WeakComparator
13
+ include Support::Logger
14
+ include Support::WeakComparator
15
15
 
16
16
  SCRATCHSPACE = '.__ss'
17
17
 
@@ -39,7 +39,7 @@ module Aladdin
39
39
  # @return [String] (json-encoded) true iff the submitted answer is correct.
40
40
  def verify_quiz
41
41
  id = @id.gsub File::SEPARATOR, '' # protect against directory attacks
42
- solution = File.expand_path id + Aladdin::DATA_EXT, Aladdin::DATA_DIR
42
+ solution = File.expand_path id + Aladdin::SOLUTION_EXT, Aladdin::DATA_DIR
43
43
  File.open(solution, 'rb') { |f| same? @params['answer'], Marshal.restore(f) }.to_json
44
44
  rescue => e
45
45
  logger.warn e.message
@@ -0,0 +1,10 @@
1
+ # ~*~ encoding: utf-8 ~*~
2
+ require 'aladdin/support/core_ext'
3
+ require 'aladdin/support/logger'
4
+ require 'aladdin/support/weak_comparator'
5
+
6
+ module Aladdin
7
+ # aladdin-support is a collection of utility classes and modules for use in
8
+ # the Aladdin project.
9
+ module Support; end
10
+ end
@@ -0,0 +1,2 @@
1
+ # ~*~ encoding: utf-8 ~*~
2
+ require 'aladdin/support/core_ext/hash'
@@ -0,0 +1,10 @@
1
+ # ~*~ encoding: utf-8 ~*~
2
+ class Hash
3
+
4
+ # Returns a struct representation of the receiver.
5
+ # @return [Struct] struct
6
+ def to_struct
7
+ Struct.new( *(k = keys) ).new( *values_at( *k ) )
8
+ end
9
+
10
+ end
@@ -0,0 +1,29 @@
1
+ # ~*~ encoding: utf-8 ~*~
2
+ require 'active_support/core_ext/logger'
3
+
4
+ module Aladdin
5
+
6
+ module Support
7
+
8
+ # Provides a convenient global logger.
9
+ # @example
10
+ # class X
11
+ # include Logger
12
+ # def x; logger.info "hey"; end
13
+ # end
14
+ # @todo FIXME allow configuration
15
+ module Logger
16
+
17
+ # Global logger.
18
+ LOGGER = ::Logger.new(STDOUT)
19
+
20
+ # Retrieves the global logger.
21
+ def logger
22
+ Logger::LOGGER
23
+ end
24
+
25
+ end
26
+
27
+ end
28
+
29
+ end
@@ -1,9 +1,9 @@
1
1
  # ~*~ encoding: utf-8 ~*~
2
2
  module Aladdin
3
3
 
4
- module Mixin
4
+ module Support
5
5
 
6
- # Provides a richer comparison with weak-typing.
6
+ # Provides a rich comparison with weak-typing.
7
7
  # @see #same?
8
8
  module WeakComparator
9
9
 
@@ -21,7 +21,7 @@ module Aladdin
21
21
  # === Numerics
22
22
  # If +saved+ is a numeric, then it will accept any +submitted+ value that
23
23
  # is numerically equivalent to +saved+. For example, if +saved+ is 0,
24
- # then +'0.0'+ and +'0'+ will both be accepted.
24
+ # then both +'0.0'+ and +'0'+ will be accepted.
25
25
  #
26
26
  # @param [String, Hash] submitted
27
27
  # @param [String, Numeric, Boolean, Hash] saved
@@ -40,9 +40,9 @@ module Aladdin
40
40
 
41
41
  private
42
42
 
43
- # Compares two hash and returns a simple diff. It checks that both
44
- # +submitted+ and +saved+ have the same number of elements, and then
45
- # compares each pair of elements in order.
43
+ # Compares two hashes and returns a simple diff. It checks that both
44
+ # +submitted+ and +saved+ have the same number of keys, and then
45
+ # compares all key-value pairs in order.
46
46
  #
47
47
  # @param [Hash] submitted
48
48
  # @param [Hash] saved
@@ -53,6 +53,8 @@ module Aladdin
53
53
  Hash[saved.map { |key, value| [key, same?(submitted[key], value)] }]
54
54
  end
55
55
 
56
+ extend self
57
+
56
58
  end
57
59
 
58
60
  end
@@ -1,4 +1,4 @@
1
1
  module Aladdin
2
2
  # Version number.
3
- VERSION = "0.0.4"
3
+ VERSION = "0.0.5"
4
4
  end
@@ -0,0 +1,3 @@
1
+ # See http://help.github.com/ignore-files/ for more about ignoring files.
2
+
3
+ .sass-cache
@@ -0,0 +1,9 @@
1
+ {
2
+ "title": "A Genie Lesson",
3
+ "description": "Hello World! Welcome to your first lesson.",
4
+ "categories": [
5
+ "ruby",
6
+ "programming",
7
+ "software"
8
+ ]
9
+ }
@@ -0,0 +1,5 @@
1
+ -# coding: UTF-8
2
+ -haml_tag ('h%d' % level).to_sym do
3
+ %a.anchor{name: name, href: '#' + name, 'data-magellan-destination' => name}
4
+ %i.foundicon-paper-clip
5
+ =text
@@ -13,6 +13,10 @@
13
13
 
14
14
  %title= title
15
15
  %link{rel: 'stylesheet', href:'stylesheets/app.css'}
16
+ %link{rel: 'stylesheet', href:'stylesheets/general_foundicons.css'}
17
+ /[if lt IE 8]
18
+ %link{rel: 'stylesheet', href:'stylesheets/general_foundicons_ie7.css'}
19
+
16
20
  %script{src: 'javascripts/foundation/modernizr.foundation.js'}
17
21
 
18
22
  %body
data/views/haml/nav.haml CHANGED
@@ -1,5 +1,5 @@
1
1
  -# coding: UTF-8
2
2
  %dl#sections.sub-nav{'data-magellan-expedition' => 'fixed'}
3
- -sections.each_with_index do |section, i|
4
- %dd{'data-magellan-arrival' => "section_#{i}"}
5
- %a{href: "#section_#{i}"}= section
3
+ -sections.each do |name, heading|
4
+ %dd{'data-magellan-arrival' => name}
5
+ %a{href: '#' + name}= heading
@@ -239,4 +239,33 @@
239
239
  // $base-size: $baseFontSize $importantModNum;
240
240
  // Produced the following list of values: 14, 17, 23, 27, 37, 44, 59, 71, 95, 115;
241
241
  // http://www.modularscale.com by Tim Brown
242
- // https://github.com/scottkellum/modular-scale by scottkellum
242
+ // https://github.com/scottkellum/modular-scale by scottkellum
243
+
244
+ $fontFileName: "/fonts/general_foundicons";
245
+ $fontName: "GeneralFoundicons";
246
+ $classPrefix: "foundicon-";
247
+
248
+ @mixin i-class($name,$pua) {
249
+ .#{$classPrefix}#{$name}:before {
250
+ content: "\f#{$pua}";
251
+ }
252
+ }
253
+
254
+ @mixin ie-class($name,$pua) {
255
+ .#{$classPrefix}#{$name} {
256
+ *zoom: expression( this.runtimeStyle['zoom'] = "1", this.innerHTML = "&#xf#{$pua};");
257
+ }
258
+ }
259
+
260
+ @mixin face {
261
+ @font-face {
262
+ font-family: $fontName;
263
+ src: url('#{$fontFileName}.eot');
264
+ src: url('#{$fontFileName}.eot?#iefix') format('embedded-opentype'),
265
+ url('#{$fontFileName}.woff') format('woff'),
266
+ url('#{$fontFileName}.ttf') format('truetype'),
267
+ url('#{$fontFileName}.svg##{$fontName}') format('svg');
268
+ font-weight: normal;
269
+ font-style: normal;
270
+ }
271
+ }
data/views/scss/app.scss CHANGED
@@ -44,11 +44,32 @@ a.hero img {
44
44
  }
45
45
 
46
46
  /* Styling within lesson */
47
+ section[role='lesson'] {
47
48
 
48
- section[role='lesson'] .block-image {
49
- text-align: center;
50
- }
49
+ .block-image {
50
+ text-align: center;
51
+ }
52
+
53
+ ul {
54
+ margin-left: 17px;
55
+ }
56
+
57
+ #{nest(headings(), 'a.anchor')} {
58
+ position: absolute;
59
+ padding-left: 60px;
60
+ margin-left: -60px;
61
+ display: block;
62
+ }
63
+
64
+ #{nest(headings(), 'a.anchor i')} {
65
+ display: none;
66
+ width: 16px;
67
+ font-size: 16px;
68
+ }
69
+
70
+ #{nest(append-selector(headings(), ':hover'), 'a.anchor i')} {
71
+ display: inline-block;
72
+ margin-left: -1.5em;
73
+ }
51
74
 
52
- section[role='lesson'] ul {
53
- margin-left: 17px;
54
75
  }
@@ -0,0 +1,71 @@
1
+ @import "settings";
2
+
3
+ /* font-face */
4
+ @include face;
5
+
6
+ /* global foundicon styles */
7
+ [class*="#{$classPrefix}"] {
8
+ display: inline;
9
+ width: auto;
10
+ height: auto;
11
+ line-height: inherit;
12
+ vertical-align: baseline;
13
+ background-image: none;
14
+ background-position: 0 0;
15
+ background-repeat: repeat;
16
+ }
17
+ [class*="#{$classPrefix}"]:before {
18
+ font-family: $fontName;
19
+ font-weight: normal;
20
+ font-style: normal;
21
+ text-decoration: inherit;
22
+ }
23
+
24
+ /* icons */
25
+ @include i-class(settings,"000");
26
+ @include i-class(heart,"001");
27
+ @include i-class(star,"002");
28
+ @include i-class(plus,"003");
29
+ @include i-class(minus,"004");
30
+ @include i-class(checkmark,"005");
31
+ @include i-class(remove,"006");
32
+ @include i-class(mail,"007");
33
+ @include i-class(calendar,"008");
34
+ @include i-class(page,"009");
35
+ @include i-class(tools,"00a");
36
+ @include i-class(globe,"00b");
37
+ @include i-class(home,"00c");
38
+ @include i-class(quote,"00d");
39
+ @include i-class(people,"00e");
40
+ @include i-class(monitor,"00f");
41
+ @include i-class(laptop,"010");
42
+ @include i-class(phone,"011");
43
+ @include i-class(cloud,"012");
44
+ @include i-class(error,"013");
45
+ @include i-class(right-arrow,"014");
46
+ @include i-class(left-arrow,"015");
47
+ @include i-class(up-arrow,"016");
48
+ @include i-class(down-arrow,"017");
49
+ @include i-class(trash,"018");
50
+ @include i-class(add-doc,"019");
51
+ @include i-class(edit,"01a");
52
+ @include i-class(lock,"01b");
53
+ @include i-class(unlock,"01c");
54
+ @include i-class(refresh,"01d");
55
+ @include i-class(paper-clip,"01e");
56
+ @include i-class(video,"01f");
57
+ @include i-class(photo,"020");
58
+ @include i-class(graph,"021");
59
+ @include i-class(idea,"022");
60
+ @include i-class(mic,"023");
61
+ @include i-class(cart,"024");
62
+ @include i-class(address-book,"025");
63
+ @include i-class(compass,"026");
64
+ @include i-class(flag,"027");
65
+ @include i-class(location,"028");
66
+ @include i-class(clock,"029");
67
+ @include i-class(folder,"02a");
68
+ @include i-class(inbox,"02b");
69
+ @include i-class(website,"02c");
70
+ @include i-class(smiley,"02d");
71
+ @include i-class(search,"02e");
@@ -0,0 +1,56 @@
1
+ @import "settings";
2
+
3
+ /* general icons for IE7 */
4
+ [class*="#{$classPrefix}"] {
5
+ font-family: $fontName;
6
+ font-weight: normal;
7
+ font-style: normal;
8
+ }
9
+
10
+ @include ie-class(settings,"000");
11
+ @include ie-class(heart,"001");
12
+ @include ie-class(star,"002");
13
+ @include ie-class(plus,"003");
14
+ @include ie-class(minus,"004");
15
+ @include ie-class(checkmark,"005");
16
+ @include ie-class(remove,"006");
17
+ @include ie-class(mail,"007");
18
+ @include ie-class(calendar,"008");
19
+ @include ie-class(page,"009");
20
+ @include ie-class(tools,"00a");
21
+ @include ie-class(globe,"00b");
22
+ @include ie-class(home,"00c");
23
+ @include ie-class(quote,"00d");
24
+ @include ie-class(people,"00e");
25
+ @include ie-class(monitor,"00f");
26
+ @include ie-class(laptop,"010");
27
+ @include ie-class(phone,"011");
28
+ @include ie-class(cloud,"012");
29
+ @include ie-class(error,"013");
30
+ @include ie-class(right-arrow,"014");
31
+ @include ie-class(left-arrow,"015");
32
+ @include ie-class(up-arrow,"016");
33
+ @include ie-class(down-arrow,"017");
34
+ @include ie-class(trash,"018");
35
+ @include ie-class(add-doc,"019");
36
+ @include ie-class(edit,"01a");
37
+ @include ie-class(lock,"01b");
38
+ @include ie-class(unlock,"01c");
39
+ @include ie-class(refresh,"01d");
40
+ @include ie-class(paper-clip,"01e");
41
+ @include ie-class(video,"01f");
42
+ @include ie-class(photo,"020");
43
+ @include ie-class(graph,"021");
44
+ @include ie-class(idea,"022");
45
+ @include ie-class(mic,"023");
46
+ @include ie-class(cart,"024");
47
+ @include ie-class(address-book,"025");
48
+ @include ie-class(compass,"026");
49
+ @include ie-class(flag,"027");
50
+ @include ie-class(location,"028");
51
+ @include ie-class(clock,"029");
52
+ @include ie-class(folder,"02a");
53
+ @include ie-class(inbox,"02b");
54
+ @include ie-class(website,"02c");
55
+ @include ie-class(smiley,"02d");
56
+ @include ie-class(search,"02e");
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aladdin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-24 00:00:00.000000000 Z
12
+ date: 2012-12-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sinatra
@@ -155,6 +155,22 @@ dependencies:
155
155
  - - ! '>='
156
156
  - !ruby/object:Gem::Version
157
157
  version: '0'
158
+ - !ruby/object:Gem::Dependency
159
+ name: activesupport
160
+ requirement: !ruby/object:Gem::Requirement
161
+ none: false
162
+ requirements:
163
+ - - ~>
164
+ - !ruby/object:Gem::Version
165
+ version: 3.2.9
166
+ type: :runtime
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ none: false
170
+ requirements:
171
+ - - ~>
172
+ - !ruby/object:Gem::Version
173
+ version: 3.2.9
158
174
  - !ruby/object:Gem::Dependency
159
175
  name: yard
160
176
  requirement: !ruby/object:Gem::Requirement
@@ -246,25 +262,37 @@ files:
246
262
  - LICENSE
247
263
  - README.md
248
264
  - lib/aladdin/app.rb
249
- - lib/aladdin/cli.rb
250
265
  - lib/aladdin/commands/new.rb
251
266
  - lib/aladdin/commands/server.rb
252
- - lib/aladdin/mixin/logger.rb
253
- - lib/aladdin/mixin/weak_comparator.rb
267
+ - lib/aladdin/commands.rb
268
+ - lib/aladdin/config.rb
269
+ - lib/aladdin/constants.rb
254
270
  - lib/aladdin/render/error.rb
255
- - lib/aladdin/render/image.rb
256
271
  - lib/aladdin/render/markdown.rb
257
- - lib/aladdin/render/multi.rb
258
- - lib/aladdin/render/navigation.rb
259
- - lib/aladdin/render/problem.rb
260
272
  - lib/aladdin/render/sanitize.rb
261
- - lib/aladdin/render/short.rb
262
- - lib/aladdin/render/table.rb
263
- - lib/aladdin/render/template.rb
273
+ - lib/aladdin/render/templates/header.rb
274
+ - lib/aladdin/render/templates/image.rb
275
+ - lib/aladdin/render/templates/multi.rb
276
+ - lib/aladdin/render/templates/navigation.rb
277
+ - lib/aladdin/render/templates/problem.rb
278
+ - lib/aladdin/render/templates/short.rb
279
+ - lib/aladdin/render/templates/table.rb
280
+ - lib/aladdin/render/templates/template.rb
281
+ - lib/aladdin/render/templates.rb
282
+ - lib/aladdin/render.rb
264
283
  - lib/aladdin/submission.rb
284
+ - lib/aladdin/support/core_ext/hash.rb
285
+ - lib/aladdin/support/core_ext.rb
286
+ - lib/aladdin/support/logger.rb
287
+ - lib/aladdin/support/weak_comparator.rb
288
+ - lib/aladdin/support.rb
265
289
  - lib/aladdin/version.rb
266
290
  - lib/aladdin.rb
267
291
  - assets/favicon.ico
292
+ - assets/fonts/general_foundicons.eot
293
+ - assets/fonts/general_foundicons.svg
294
+ - assets/fonts/general_foundicons.ttf
295
+ - assets/fonts/general_foundicons.woff
268
296
  - assets/images/graphic.png
269
297
  - assets/images/no_gravatar.gif
270
298
  - assets/javascripts/app.js
@@ -291,6 +319,7 @@ files:
291
319
  - assets/javascripts/foundation/jquery.placeholder.js
292
320
  - assets/javascripts/foundation/modernizr.foundation.js
293
321
  - views/haml/exe.haml
322
+ - views/haml/header.haml
294
323
  - views/haml/img.haml
295
324
  - views/haml/layout.haml
296
325
  - views/haml/multi.haml
@@ -303,9 +332,13 @@ files:
303
332
  - views/scss/_pygment.scss
304
333
  - views/scss/_settings.scss
305
334
  - views/scss/app.scss
335
+ - views/scss/general_foundicons.scss
336
+ - views/scss/general_foundicons_ie7.scss
306
337
  - bin/aladdin
338
+ - skeleton/gitignore
307
339
  - skeleton/images/graphic.png
308
340
  - skeleton/index.md
341
+ - skeleton/manifest.json
309
342
  homepage: https://github.com/jimjh/aladdin
310
343
  licenses:
311
344
  - MIT
data/lib/aladdin/cli.rb DELETED
@@ -1,29 +0,0 @@
1
- # ~*~ encoding: utf-8 ~*~
2
-
3
- Signal.trap('INT') { puts; exit(1) }
4
-
5
- case ARGV.first
6
- when '--version', '-v'
7
- puts "Aladdin #{Aladdin::VERSION}"
8
- exit(0)
9
- when 'new'
10
- ARGV.shift
11
- require_relative 'commands/new'
12
- when 'server'
13
- ARGV.shift
14
- require_relative 'commands/server'
15
- else
16
- puts <<-eos
17
- Usage:
18
- aladdin COMMAND [options]
19
-
20
- Commands:
21
- new # generates the skeleton for a new lesson
22
- server # launches a preview server
23
-
24
- Aladdin Options:
25
- -v, [--version] # show version number and quit
26
- -h, [--help] # show this help message and quit
27
- eos
28
- exit ['-h', '--help'].include?(ARGV.first) ? 0 : 1
29
- end
@@ -1,26 +0,0 @@
1
- # ~*~ encoding: utf-8 ~*~
2
- require 'logger'
3
-
4
- module Aladdin
5
-
6
- # aladdin-mixin module contains all other mixin modules.
7
- module Mixin
8
-
9
- # @example
10
- # require 'logger'
11
- # logger.info "hey"
12
- module Logger
13
-
14
- # Global Logger.
15
- LOGGER = ::Logger.new STDOUT
16
-
17
- # Retrieves the global logger.
18
- def logger
19
- Logger::LOGGER
20
- end
21
-
22
- end
23
-
24
- end
25
-
26
- end