cc2html 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1 @@
1
+ 1.9.3-p392
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cc2html (0.1.0)
4
+ cc2html (0.0.2)
5
5
  builder
6
6
  happymapper
7
7
  nokogiri
@@ -39,9 +39,9 @@ GEM
39
39
  rb-inotify (>= 0.9)
40
40
  lumberjack (1.0.4)
41
41
  method_source (0.8.2)
42
- mini_portile (0.5.2)
42
+ mini_portile (0.5.3)
43
43
  minitest (5.0.8)
44
- nokogiri (1.6.0)
44
+ nokogiri (1.6.1)
45
45
  mini_portile (~> 0.5.0)
46
46
  pry (0.9.12.2)
47
47
  coderay (~> 1.0.5)
@@ -51,8 +51,8 @@ GEM
51
51
  rb-fsevent (0.9.3)
52
52
  rb-inotify (0.9.2)
53
53
  ffi (>= 0.5.0)
54
- rdiscount (2.1.7)
55
- rubyzip (1.1.0)
54
+ rdiscount (2.1.7.1)
55
+ rubyzip (1.1.3)
56
56
  slop (3.4.6)
57
57
  thor (0.18.1)
58
58
  timers (1.1.0)
data/README.md CHANGED
@@ -15,22 +15,27 @@ Once RubyGems is installed you can install this gem:
15
15
 
16
16
  $ gem install cc2html
17
17
 
18
- Convert a Common Cartridge into HTML
18
+ Convert a Common Cartridge into EPUB
19
19
 
20
- $ cc2html migrate <path-to-cc-backup> <path-to-html-export-directory>
20
+ $ cc2html convert --format=epub <path-to-cc-backup> <name-of-epub-without-extension>
21
21
 
22
- Or into an epub
22
+ Or into HTML (mostly broken) :)
23
23
 
24
- $ cc2html migrate <path-to-cc-backup> <path-to-epub-export-directory> --format=epub
25
- # then zip of the contents of the folder into a .epub
24
+ $ cc2html convert <path-to-cc-backup> <path-to-html-export-directory>
26
25
 
27
26
  ## Todo
28
27
 
29
- * Oh so much!
30
- * Support converting all Common Cartridge versions
31
- * Create chapters from organization sections
32
- * Quiz conversion
33
- * make epub zip automatically
28
+ - [ ] Oh so much!
29
+ - [ ] Support converting all Common Cartridge versions
30
+ - [x] Create chapters from organization sections
31
+ - [ ] Quiz conversion
32
+ - [ ] Styles so it looks good
33
+ - [ ] Configurable styles
34
+ - [ ] Write epub/html output tests
35
+ - [ ] Make HTML output work
36
+ - [ ] Make HTML/EPUB code more DRY
37
+ - [ ] Handle CC weblink/topic/assignment/LTI types better
38
+ - [x] Automatically zip up epub
34
39
 
35
40
  ## Contributing
36
41
 
@@ -1,9 +1,10 @@
1
1
  module CC2HTML
2
2
  class Builder
3
- def initialize(manifest, dest_dir)
4
- @dest_dir = dest_dir
3
+ def initialize(manifest, dest_name)
4
+ @dest_name = dest_name
5
5
  @manifest = manifest
6
- @items = manifest.organizations.organization.item.items
6
+ @root_items = manifest.organizations.organization.item.items
7
+ @resources = manifest.resources.resources
7
8
  lom = manifest.metadata.lom
8
9
  @title = lom.general.title.title
9
10
  @description = lom.general.description.description if lom.general.description
@@ -2,14 +2,16 @@ require 'thor'
2
2
 
3
3
  module CC2HTML
4
4
  class CLI < Thor
5
- desc "migrate COMMON_CARTRIDGE_ZIP EXPORT_DIR", "Migrates Common Cartridge ZIP to an HTML representation"
5
+ desc "convert --format epub COMMON_CARTRIDGE_ZIP EXPORT_NAME", "Migrates Common Cartridge ZIP to an HTML or EPUB representation"
6
6
  method_option :format, :default => 'html'
7
7
  method_options :format => :string
8
+ method_option :leave_unzipped, :default => false
9
+ method_options :leave_unzipped => :boolean
8
10
 
9
- def migrate(source, destination)
11
+ def convert(source, destination)
10
12
  converter = CC2HTML::Converter.new source, destination, options
11
13
  converter.convert
12
- puts "#{source} converted to #{converter.cc_file_path}"
14
+ puts "#{source} converted to #{destination}.epub"
13
15
  end
14
16
  end
15
17
  end
@@ -2,18 +2,18 @@ module CC2HTML
2
2
  class Converter
3
3
  attr_reader :cc_file_path, :dest_dir
4
4
 
5
- def initialize(cc_file_path, dest_dir, options={})
5
+ def initialize(cc_file_path, dest_name, options={})
6
6
  @cc_file_path = cc_file_path
7
- @dest_dir = dest_dir
7
+ @dest_name = dest_name
8
8
  @settings = options
9
9
  end
10
10
 
11
11
  def convert
12
12
  manifest = IMS::CC::Manifest.read(@cc_file_path)
13
13
  if @settings[:format] == 'html'
14
- CC2HTML::HtmlBuilder.new(manifest, @dest_dir, @cc_file_path).generate
14
+ CC2HTML::HtmlBuilder.new(manifest, @dest_name, @cc_file_path).generate
15
15
  elsif @settings[:format] == 'epub'
16
- CC2HTML::EpubBuilder.new(manifest, @dest_dir, @cc_file_path).generate
16
+ CC2HTML::EpubBuilder.new(manifest, @dest_name, @cc_file_path, @settings).generate
17
17
  end
18
18
  end
19
19
 
@@ -2,34 +2,51 @@ module CC2HTML
2
2
  class EpubBuilder < Builder
3
3
  TEMPLATE_DIR = '../templates/epub/'
4
4
 
5
- def initialize(manifest, dest_dir, zip_file=nil)
6
- super(manifest, dest_dir)
5
+ def initialize(manifest, dest_name, zip_file, opts={})
6
+ super(manifest, dest_name)
7
7
  @file_name = 'cc_book'
8
- @content_dir = File.join(@dest_dir, 'content')
8
+ @content_dir = File.join(@dest_name, 'content')
9
9
  @zip_file = zip_file
10
- @items_with_resource = @items.select{|i|i.resource}
10
+ @items_with_resource = @manifest.organizations.organization.item.all_items.select{|i|i.resource}
11
+ @leave_in_folder = opts["leave_unzipped"]
11
12
  end
12
13
 
13
14
  def generate
14
- FileUtils.mkdir_p(@dest_dir)
15
+ FileUtils.mkdir_p(@dest_name)
15
16
  create_mimetype_file
16
17
  create_meta_inf
17
18
  FileUtils.mkdir_p(@content_dir)
18
19
  create_opf
19
20
  create_nav
20
21
  create_chapters
21
- copy_html_webresources
22
+ copy_images
23
+ copy_referenced_html_webresources
24
+ compress_into_epub
25
+ end
26
+
27
+ def compress_into_epub
28
+ unless @leave_in_folder
29
+ epub = @dest_name + '.epub'
30
+ FileUtils.rm(epub) if File.exists?(epub)
31
+ Zip::File.open(epub, Zip::File::CREATE) do |zipfile|
32
+ Dir["#{@dest_name}/**/**"].each do |file|
33
+ file_path = file.sub(@dest_name+'/', '')
34
+ zipfile.add(file_path, file)
35
+ end
36
+ end
37
+ FileUtils.rmtree(@dest_name)
38
+ end
22
39
  end
23
40
 
24
41
  def create_mimetype_file
25
- File.open(File.join(@dest_dir, 'mimetype'), 'w') do |f|
42
+ File.open(File.join(@dest_name, 'mimetype'), 'w') do |f|
26
43
  f << "application/epub+zip\n"
27
44
  end
28
45
  end
29
46
 
30
47
  def create_nav
31
48
  template = File.expand_path(TEMPLATE_DIR + 'navigation.html.erb', __FILE__)
32
- path = File.join(@content_dir = File.join(@dest_dir, 'content'), 'navigation.html')
49
+ path = File.join(@content_dir, 'navigation.html')
33
50
 
34
51
  File.open(path, 'w') do |file|
35
52
  erb = ERB.new(File.read(template))
@@ -43,7 +60,7 @@ module CC2HTML
43
60
  next if item.resource.type == 'webcontent'
44
61
  # so stupid... I'll fix later. :)
45
62
  @item = item
46
- path = File.join(@content_dir = File.join(@dest_dir, 'content'), item.identifierref + '.html')
63
+ path = File.join(@content_dir, item.identifierref + '.html')
47
64
  File.open(path, 'w') do |file|
48
65
  erb = ERB.new(File.read(template))
49
66
  file.write(erb.result(binding))
@@ -51,15 +68,34 @@ module CC2HTML
51
68
  end
52
69
  end
53
70
 
54
- def copy_html_webresources
71
+ def copy_referenced_html_webresources
55
72
  return unless @zip_file.end_with?('zip') || @zip_file.end_with?('imscc')
56
73
  Zip::File.open(@zip_file) do |zipfile|
57
74
  @items_with_resource.each do |item|
58
75
  if item.resource.type == 'webcontent' && item.resource.href && item.resource.href.end_with?('html')
59
- puts item.identifier
60
- path = File.join(@content_dir = File.join(@dest_dir, 'content'), item.identifierref + '.html')
76
+ path = File.join(@content_dir = File.join(@dest_name, 'content'), item.identifierref + '.html')
61
77
  File.open(path, 'w') do |file|
62
78
  entry = zipfile.get_entry(item.resource.href)
79
+ val = entry.get_input_stream.read
80
+ file << val.gsub('%24IMS_CC_FILEBASE%24', 'web_resources')
81
+ # file << entry.get_input_stream.read
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+
88
+ def copy_images
89
+ return unless @zip_file.end_with?('zip') || @zip_file.end_with?('imscc')
90
+ Zip::File.open(@zip_file) do |zipfile|
91
+ @resources.each do |resource|
92
+ if resource.type == 'webcontent' && resource.href &&
93
+ resource.href.start_with?('web_resources') &&
94
+ File.extname(resource.href) =~ /gif|jpg|png/i
95
+ path = File.join(@content_dir, resource.href)
96
+ FileUtils.mkdir_p(File.dirname(path))
97
+ File.open(path, 'w') do |file|
98
+ entry = zipfile.get_entry(resource.href)
63
99
  file << entry.get_input_stream.read
64
100
  end
65
101
  end
@@ -68,7 +104,7 @@ module CC2HTML
68
104
  end
69
105
 
70
106
  def create_meta_inf
71
- meta_dir = File.join(@dest_dir, 'META-INF')
107
+ meta_dir = File.join(@dest_name, 'META-INF')
72
108
  FileUtils.mkdir_p(meta_dir)
73
109
  File.open(File.join(meta_dir, 'container.xml'), 'w') do |f|
74
110
  f << <<-XML
@@ -84,7 +120,7 @@ XML
84
120
 
85
121
  def create_opf
86
122
  template = File.expand_path(TEMPLATE_DIR + 'descriptor.opf.erb', __FILE__)
87
- path = File.join(@content_dir = File.join(@dest_dir, 'content'), @file_name + '.opf')
123
+ path = File.join(@content_dir, @file_name + '.opf')
88
124
 
89
125
  File.open(path, 'w') do |file|
90
126
  erb = ERB.new(File.read(template))
@@ -3,14 +3,14 @@ module CC2HTML
3
3
  TEMPLATE_DIR = '../templates/html/'
4
4
  def initialize(manifest, dest_dir, zip_file)
5
5
  @manifest = manifest
6
- @dest_dir = dest_dir
7
- @items = manifest.organizations.organization.item.items
6
+ @dest_name = dest_dir
7
+ @root_items = manifest.organizations.organization.item.items
8
8
  end
9
9
 
10
10
  def generate
11
- FileUtils.mkdir_p(@dest_dir)
11
+ FileUtils.mkdir_p(@dest_name)
12
12
  template = File.expand_path(TEMPLATE_DIR + 'index.html.erb', __FILE__)
13
- path = File.join(@dest_dir, 'index.html')
13
+ path = File.join(@dest_name, 'index.html')
14
14
 
15
15
  #FileUtils.mkdir_p(File.dirname(path))
16
16
  File.open(path, 'w') do |file|
@@ -1,11 +1,22 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
2
  <html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops">
3
- <head><title>Table of contents</title></head>
4
- <body><nav xmlns="http://www.w3.org/1999/xhtml" class="book" epub:type="toc">
5
- <ol>
6
- <% @items.each do |item| %>
7
- <li><a href="<%= item.identifierref %>.html"><%= item.title %></a></li>
8
- <% end %>
9
- </ol>
10
- </nav></body>
3
+ <head><title>Table of contents</title></head>
4
+ <body>
5
+ <nav xmlns="http://www.w3.org/1999/xhtml" class="book" epub:type="toc">
6
+ <% @root_items.select{|ri|ri.items.any?}.each_with_index do |root, chapter_index| %>
7
+ <h2>Chaper <%= chapter_index + 1 %>: <%= root.title %></h2>
8
+
9
+ <ol>
10
+ <% root.items.each do |item| %>
11
+ <% if item.identifierref && item.identifierref != '' %>
12
+ <li><a href="<%= item.identifierref %>.html"><%= item.title %></a></li>
13
+ <% else %>
14
+ <!-- Could have sub headers in index, but may only appropriate for pages -->
15
+ <!--<h3><%= item.title %></h3>-->
16
+ <% end %>
17
+ <% end %>
18
+ </ol>
19
+ <% end %>
20
+ </nav>
21
+ </body>
11
22
  </html>
@@ -5,7 +5,7 @@
5
5
  </head>
6
6
  <body>
7
7
  <ul>
8
- <% @items.each do |item| %>
8
+ <% @root_items.each do |item| %>
9
9
  <li><%= item.identifier %></li>
10
10
  <% end %>
11
11
  </ul>
@@ -1,3 +1,3 @@
1
1
  module CC2HTML
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -29,16 +29,7 @@ module IMS::CC
29
29
 
30
30
  def post_process
31
31
  parse_references
32
- connect_resources_to_org_item
33
- end
34
-
35
- def connect_resources_to_org_item
36
- self.organizations.organization.item.items.each do |item|
37
- next unless item.identifierref
38
- if res = self.resources.find_by_identifier(item.identifierref)
39
- item.resource = res
40
- end
41
- end
32
+ organizations.attach_resources_to_items(resources)
42
33
  end
43
34
 
44
35
  def parse_references
@@ -10,7 +10,33 @@ module Organizations
10
10
  attribute :identifierref, String
11
11
  element :title, String
12
12
 
13
- has_many :items, Item
13
+ # This is so that it only select parent items of itself,
14
+ # otherwise HappyMapper does .// instead of ./
15
+ # can this reference its own namespace somehow?
16
+ has_many :items, Item, :xpath => "./#{HappyMapper::DEFAULT_NS}:item"
17
+
18
+ def find_by_identifier(id)
19
+ if id == identifier
20
+ self
21
+ else
22
+ items.each do |i|
23
+ if item = i.find_by_identifier(id)
24
+ return item
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ def attach_resources(resources)
31
+ @resource = resources.find_by_identifier(identifierref) if identifierref
32
+ items.each { |i| i.attach_resources(resources) }
33
+ end
34
+
35
+ def all_items(res=[])
36
+ res << self
37
+ items.each{|i|i.all_items(res)}
38
+ res
39
+ end
14
40
  end
15
41
 
16
42
  class Organization
@@ -29,7 +55,11 @@ module Organizations
29
55
  has_one :organization, Organization
30
56
 
31
57
  def find_item_by_identifier(id)
32
- self.organization.item.items.find{|i| i.identifier == id}
58
+ organization.item.find_by_identifier(id)
59
+ end
60
+
61
+ def attach_resources_to_items(resources)
62
+ organization.item.attach_resources(resources)
33
63
  end
34
64
  end
35
65
 
@@ -1,10 +1,10 @@
1
1
  module IMS::CC
2
2
  class Topic
3
3
  include HappyMapper
4
- #register_namespace('http://www.imsglobal.org/xsd/imsccv1p3/imsdt_v1p3', 'dt3')
5
- #register_namespace('http://www.imsglobal.org/xsd/imsccv1p1/imsdt_v1p1', 'dt1')
4
+ # register_namespace('http://www.imsglobal.org/xsd/imsccv1p3/imsdt_v1p3', 'dt3')
5
+ # register_namespace('http://www.imsglobal.org/xsd/imsccv1p1/imsdt_v1p1', 'dt1')
6
6
  namespace 'http://www.imsglobal.org/xsd/imsccv1p3/imsdt_v1p3'
7
- #namespace 'http://www.imsglobal.org/xsd/imsccv1p1/imsdt_v1p1'
7
+ # namespace 'http://www.imsglobal.org/xsd/imsccv1p1/imsdt_v1p1'
8
8
 
9
9
  tag 'topic'
10
10
  element :title, String
@@ -59,7 +59,16 @@
59
59
  <item identifier="I_00003" identifierref="Resource3">
60
60
  <title>Open2.net</title>
61
61
  </item>
62
- <item identifier="I_00004" identifierref="Resource4">
62
+ <item identifier="I_00003">
63
+ <title>Child Folder</title>
64
+ <item identifier="I_00004" identifierref="Resource4">
65
+ <title>LTI Launch</title>
66
+ </item>
67
+ </item>
68
+ </item>
69
+ <item identifier="I_2">
70
+ <title>Folder 2</title>
71
+ <item identifier="I_00005" identifierref="Resource4">
63
72
  <title>LTI Launch</title>
64
73
  </item>
65
74
  </item>
@@ -14,20 +14,41 @@ class TestUnitOrganizations < Minitest::Test
14
14
  assert_equal 'rooted-hierarchy', @orgs.organization.structure
15
15
  end
16
16
 
17
- # have to figure out why happy mapper gets all items instead of just 1st children
18
- #def test_it_creates_item_tree
19
- # assert_equal 1, @orgs.organization.item.items.count
20
- # assert_equal 4, @orgs.organization.item.items[0].count
21
- #end
17
+ def test_it_creates_item_tree
18
+ assert_instance_of IMS::CC::Organizations::Item, @orgs.organization.item
19
+ assert_equal 2, @orgs.organization.item.items.count
20
+ assert_equal 4, @orgs.organization.item.items[0].items.count
21
+ assert_equal 1, @orgs.organization.item.items[0].items[3].items.count
22
+ assert_equal 1, @orgs.organization.item.items[1].items.count
23
+ end
22
24
 
23
25
  def test_gets_item_info
24
- assert_equal "I_00000", @orgs.organization.item.items[0].identifier
25
- assert_equal "CCv1.3 With Assignment", @orgs.organization.item.items[0].title
26
- assert_equal '', @orgs.organization.item.items[0].identifierref
27
-
28
- assert_equal "I_00001", @orgs.organization.item.items[1].identifier
29
- assert_equal "Cool Assignment", @orgs.organization.item.items[1].title
30
- assert_equal "Resource1", @orgs.organization.item.items[1].identifierref
26
+ folder1 = @orgs.organization.item.items[0]
27
+ assert_equal "I_00000", folder1.identifier
28
+ assert_equal "CCv1.3 With Assignment", folder1.title
29
+ assert_equal '', folder1.identifierref
30
+
31
+ assert_equal "I_00001", folder1.items[0].identifier
32
+ assert_equal "Cool Assignment", folder1.items[0].title
33
+ assert_equal "Resource1", folder1.items[0].identifierref
34
+
35
+ sub_folder = folder1.items.last
36
+ assert_equal "I_00003", sub_folder.identifier
37
+ assert_equal "Child Folder", sub_folder.title
38
+ assert_equal "", sub_folder.identifierref
39
+
40
+ assert_equal "I_00004", sub_folder.items[0].identifier
41
+ assert_equal "LTI Launch", sub_folder.items[0].title
42
+ assert_equal "Resource4", sub_folder.items[0].identifierref
43
+
44
+ folder2 = @orgs.organization.item.items[1]
45
+ assert_equal "I_2", folder2.identifier
46
+ assert_equal "Folder 2", folder2.title
47
+ assert_equal "", folder2.identifierref
48
+
49
+ assert_equal "I_00005", folder2.items[0].identifier
50
+ assert_equal "LTI Launch", folder2.items[0].title
51
+ assert_equal "Resource4", folder2.items[0].identifierref
31
52
  end
32
53
 
33
54
  def test_item_references_resource
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cc2html
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
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: 2013-11-11 00:00:00.000000000 Z
12
+ date: 2014-05-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rubyzip
@@ -196,6 +196,7 @@ extensions: []
196
196
  extra_rdoc_files:
197
197
  - LICENSE
198
198
  files:
199
+ - .ruby-version
199
200
  - Gemfile
200
201
  - Gemfile.lock
201
202
  - Guardfile