aladdin 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
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