locomotivecms_mounter 1.0.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. data/lib/locomotive/mounter/config.rb +21 -0
  2. data/lib/locomotive/mounter/engine_api.rb +40 -0
  3. data/lib/locomotive/mounter/exceptions.rb +38 -0
  4. data/lib/locomotive/mounter/extensions/compass.rb +36 -0
  5. data/lib/locomotive/mounter/extensions/httmultiparty.rb +22 -0
  6. data/lib/locomotive/mounter/extensions/tilt/css.rb +31 -0
  7. data/lib/locomotive/mounter/extensions/tilt/haml.rb +27 -0
  8. data/lib/locomotive/mounter/extensions/tilt/liquid.rb +23 -0
  9. data/lib/locomotive/mounter/extensions/tilt/template.rb +11 -0
  10. data/lib/locomotive/mounter/fields.rb +250 -0
  11. data/lib/locomotive/mounter/models/base.rb +41 -0
  12. data/lib/locomotive/mounter/models/content_asset.rb +84 -0
  13. data/lib/locomotive/mounter/models/content_entry.rb +290 -0
  14. data/lib/locomotive/mounter/models/content_field.rb +128 -0
  15. data/lib/locomotive/mounter/models/content_select_option.rb +29 -0
  16. data/lib/locomotive/mounter/models/content_type.rb +217 -0
  17. data/lib/locomotive/mounter/models/editable_element.rb +27 -0
  18. data/lib/locomotive/mounter/models/page.rb +377 -0
  19. data/lib/locomotive/mounter/models/site.rb +27 -0
  20. data/lib/locomotive/mounter/models/snippet.rb +55 -0
  21. data/lib/locomotive/mounter/models/theme_asset.rb +135 -0
  22. data/lib/locomotive/mounter/models/translation.rb +28 -0
  23. data/lib/locomotive/mounter/mounting_point.rb +49 -0
  24. data/lib/locomotive/mounter/reader/api/base.rb +49 -0
  25. data/lib/locomotive/mounter/reader/api/content_assets_reader.rb +40 -0
  26. data/lib/locomotive/mounter/reader/api/content_entries_reader.rb +141 -0
  27. data/lib/locomotive/mounter/reader/api/content_types_reader.rb +74 -0
  28. data/lib/locomotive/mounter/reader/api/pages_reader.rb +174 -0
  29. data/lib/locomotive/mounter/reader/api/site_reader.rb +37 -0
  30. data/lib/locomotive/mounter/reader/api/snippets_reader.rb +59 -0
  31. data/lib/locomotive/mounter/reader/api/theme_assets_reader.rb +42 -0
  32. data/lib/locomotive/mounter/reader/api/translations_reader.rb +28 -0
  33. data/lib/locomotive/mounter/reader/api.rb +49 -0
  34. data/lib/locomotive/mounter/reader/file_system/base.rb +65 -0
  35. data/lib/locomotive/mounter/reader/file_system/content_assets_reader.rb +88 -0
  36. data/lib/locomotive/mounter/reader/file_system/content_entries_reader.rb +101 -0
  37. data/lib/locomotive/mounter/reader/file_system/content_types_reader.rb +88 -0
  38. data/lib/locomotive/mounter/reader/file_system/pages_reader.rb +206 -0
  39. data/lib/locomotive/mounter/reader/file_system/site_reader.rb +24 -0
  40. data/lib/locomotive/mounter/reader/file_system/snippets_reader.rb +78 -0
  41. data/lib/locomotive/mounter/reader/file_system/theme_assets_reader.rb +78 -0
  42. data/lib/locomotive/mounter/reader/file_system/translations_reader.rb +36 -0
  43. data/lib/locomotive/mounter/reader/file_system.rb +42 -0
  44. data/lib/locomotive/mounter/reader/runner.rb +89 -0
  45. data/lib/locomotive/mounter/utils/hash.rb +31 -0
  46. data/lib/locomotive/mounter/utils/string.rb +17 -0
  47. data/lib/locomotive/mounter/utils/yaml.rb +125 -0
  48. data/lib/locomotive/mounter/version.rb +8 -0
  49. data/lib/locomotive/mounter/writer/api/base.rb +323 -0
  50. data/lib/locomotive/mounter/writer/api/content_assets_writer.rb +74 -0
  51. data/lib/locomotive/mounter/writer/api/content_entries_writer.rb +223 -0
  52. data/lib/locomotive/mounter/writer/api/content_types_writer.rb +151 -0
  53. data/lib/locomotive/mounter/writer/api/pages_writer.rb +225 -0
  54. data/lib/locomotive/mounter/writer/api/site_writer.rb +164 -0
  55. data/lib/locomotive/mounter/writer/api/snippets_writer.rb +111 -0
  56. data/lib/locomotive/mounter/writer/api/theme_assets_writer.rb +152 -0
  57. data/lib/locomotive/mounter/writer/api/translations_writer.rb +83 -0
  58. data/lib/locomotive/mounter/writer/api.rb +62 -0
  59. data/lib/locomotive/mounter/writer/file_system/base.rb +61 -0
  60. data/lib/locomotive/mounter/writer/file_system/content_assets_writer.rb +33 -0
  61. data/lib/locomotive/mounter/writer/file_system/content_entries_writer.rb +29 -0
  62. data/lib/locomotive/mounter/writer/file_system/content_types_writer.rb +27 -0
  63. data/lib/locomotive/mounter/writer/file_system/pages_writer.rb +73 -0
  64. data/lib/locomotive/mounter/writer/file_system/site_writer.rb +25 -0
  65. data/lib/locomotive/mounter/writer/file_system/snippets_writer.rb +54 -0
  66. data/lib/locomotive/mounter/writer/file_system/theme_assets_writer.rb +35 -0
  67. data/lib/locomotive/mounter/writer/file_system/translations_writer.rb +22 -0
  68. data/lib/locomotive/mounter/writer/file_system.rb +69 -0
  69. data/lib/locomotive/mounter/writer/runner.rb +68 -0
  70. data/lib/locomotive/mounter.rb +97 -0
  71. metadata +487 -0
@@ -0,0 +1,78 @@
1
+ module Locomotive
2
+ module Mounter
3
+ module Reader
4
+ module FileSystem
5
+
6
+ class ThemeAssetsReader < Base
7
+
8
+ # Build the list of theme assets from the public folder with eager loading.
9
+ #
10
+ # @return [ Array ] The cached list of theme assets
11
+ #
12
+ def read
13
+ ThemeAssetsArray.new(self.root_dir)
14
+ end
15
+
16
+ protected
17
+
18
+ # Return the directory where all the theme assets
19
+ # are stored in the filesystem.
20
+ #
21
+ # @return [ String ] The theme assets directory
22
+ #
23
+ def root_dir
24
+ File.join(self.runner.path, 'public')
25
+ end
26
+
27
+ end
28
+
29
+ end
30
+
31
+ class ThemeAssetsArray
32
+
33
+ attr_accessor :root_dir
34
+
35
+ def initialize(root_dir)
36
+ self.root_dir = root_dir
37
+ end
38
+
39
+ def list
40
+ return @list unless @list.nil?
41
+
42
+ @list = [].tap do |list|
43
+ Dir.glob(File.join(self.root_dir, '**/*')).each do |file|
44
+ next if self.exclude?(file)
45
+
46
+ folder = File.dirname(file.gsub(self.root_dir, ''))
47
+
48
+ asset = Locomotive::Mounter::Models::ThemeAsset.new(folder: folder, filepath: file)
49
+
50
+ list << asset
51
+ end
52
+ end
53
+ end
54
+
55
+ # Tell if the file has to be excluded from the array
56
+ # of theme assets. It does not have to be a folder
57
+ # or be in the samples folder or owns a name starting with
58
+ # the underscore character.
59
+ #
60
+ # @param [ String ] file The full path to the file
61
+ #
62
+ # @return [ Boolean ] True if it does not have to be included in the list.
63
+ #
64
+ def exclude?(file)
65
+ File.directory?(file) ||
66
+ file.starts_with?(File.join(self.root_dir, 'samples')) ||
67
+ File.basename(file).starts_with?('_')
68
+ end
69
+
70
+ # This class acts a proxy of an array
71
+ def method_missing(name, *args, &block)
72
+ self.list.send(name.to_sym, *args, &block)
73
+ end
74
+
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,36 @@
1
+ module Locomotive
2
+ module Mounter
3
+ module Reader
4
+ module FileSystem
5
+
6
+ class TranslationsReader < Base
7
+
8
+ # Build the list of translations based on the config/translations.yml file
9
+ #
10
+ # @return [ Hash ] Hash whose the key is the translation key
11
+ #
12
+ def read
13
+ config_path = File.join(self.runner.path, 'config', 'translations.yml')
14
+
15
+ {}.tap do |translations|
16
+ if File.exists?(config_path)
17
+ self.read_yaml(config_path).each do |translation|
18
+ key, values = translation
19
+
20
+ entry = Locomotive::Mounter::Models::Translation.new({
21
+ key: key,
22
+ values: values
23
+ })
24
+
25
+ translations[key] = entry
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ end
32
+
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,42 @@
1
+ module Locomotive
2
+ module Mounter
3
+ module Reader
4
+ module FileSystem
5
+
6
+ # Build a singleton instance of the Runner class.
7
+ #
8
+ # @return [ Object ] A singleton instance of the Runner class
9
+ #
10
+ def self.instance
11
+ @@instance ||= Runner.new(:file_system)
12
+ end
13
+
14
+ class Runner < Locomotive::Mounter::Reader::Runner
15
+
16
+ attr_accessor :path
17
+
18
+ # Compass is required
19
+ def prepare
20
+ self.path = parameters.delete(:path)
21
+
22
+ if self.path.blank? || !File.exists?(self.path)
23
+ raise Locomotive::Mounter::ReaderException.new('path is required and must exist')
24
+ end
25
+
26
+ Locomotive::Mounter::Extensions::Compass.configure(self.path)
27
+ end
28
+
29
+ # Ordered list of atomic readers
30
+ #
31
+ # @return [ Array ] List of classes
32
+ #
33
+ def readers
34
+ [SiteReader, ContentTypesReader, PagesReader, SnippetsReader, ContentEntriesReader, ContentAssetsReader, ThemeAssetsReader, TranslationsReader]
35
+ end
36
+
37
+ end
38
+
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,89 @@
1
+ module Locomotive
2
+ module Mounter
3
+ module Reader
4
+
5
+ class Runner
6
+
7
+ attr_accessor :kind, :parameters, :mounting_point
8
+
9
+ def initialize(kind)
10
+ self.kind = kind
11
+
12
+ # avoid to load all the ruby files at the startup, only when we need it
13
+ base_dir = File.join(File.dirname(__FILE__), kind.to_s)
14
+ require File.join(base_dir, 'base.rb')
15
+ Dir[File.join(base_dir, '*.rb')].each { |lib| require lib }
16
+ end
17
+
18
+ # Read the content of a site (pages, snippets, ...etc) and create the corresponding mounting point.
19
+ #
20
+ # @param [ Hash ] parameters The parameters.
21
+ #
22
+ # @return [ Object ] The mounting point object storing all the information about the site
23
+ #
24
+ def run!(parameters = {})
25
+ self.parameters = parameters.symbolize_keys
26
+
27
+ self.prepare
28
+
29
+ self.build_mounting_point
30
+ end
31
+
32
+ # Reload with the same origin parameters a part of a site from a list of
33
+ # resources each described by a simple name (site, pages, ...etc) taken from
34
+ # the corresponding reader class name.
35
+ #
36
+ # @param [ Array/ String ] list An array of resource(s) or just the resource
37
+ #
38
+ def reload(*list)
39
+ Locomotive::Mounter.with_locale(self.mounting_point.default_locale) do
40
+ [*list].flatten.each do |name|
41
+ reader_name = "#{name.to_s.camelize}Reader"
42
+
43
+ reader = self.readers.detect do |_reader|
44
+ _reader.name.demodulize == reader_name
45
+ end
46
+
47
+ if reader
48
+ self.mounting_point.register_resource(name, reader.new(self).read)
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ # Before building the mounting point.
55
+ # Can be defined by reader runners
56
+ def prepare
57
+ end
58
+
59
+ # Ordered list of atomic readers
60
+ #
61
+ # @return [ Array ] List of classes
62
+ #
63
+ def readers
64
+ raise Locomotive::Mounter::ImplementationIsMissingException.new('readers are missing')
65
+ end
66
+
67
+ protected
68
+
69
+ def build_mounting_point
70
+ Locomotive::Mounter::MountingPoint.new.tap do |mounting_point|
71
+ self.mounting_point = mounting_point
72
+
73
+ self.readers.each do |reader|
74
+ name = reader.name.gsub(/(Reader)$/, '').demodulize.underscore
75
+
76
+ self.mounting_point.register_resource(name, reader.new(self).read)
77
+ end
78
+
79
+ if self.respond_to?(:path)
80
+ self.mounting_point.path = self.path
81
+ end
82
+ end
83
+ end
84
+
85
+ end
86
+
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,31 @@
1
+ unless Hash.instance_methods.include?(:deep_stringify_keys)
2
+ class Hash
3
+
4
+ # Return a new hash with all keys converted to strings.
5
+ # This includes the keys from the root hash and from all
6
+ # nested hashes.
7
+ def deep_stringify_keys
8
+ result = {}
9
+ each do |key, value|
10
+ result[key.to_s] = value.is_a?(Hash) ? value.deep_stringify_keys : value
11
+ end
12
+ result
13
+ end
14
+
15
+ end
16
+ end
17
+
18
+ unless Hash.instance_methods.include?(:deep_symbolize_keys)
19
+ class Hash
20
+
21
+ # See http://iain.nl/writing-yaml-files
22
+ def deep_symbolize_keys
23
+ {}.tap do |new_hash|
24
+ self.each do |key, value|
25
+ new_hash.merge!(key.to_sym => (value.is_a?(Hash) ? value.deep_symbolize_keys : value))
26
+ end
27
+ end
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,17 @@
1
+ # encoding: utf-8
2
+
3
+ ## String
4
+
5
+ class String #:nodoc
6
+
7
+ def permalink
8
+ self.to_ascii.parameterize('-')
9
+ end
10
+
11
+ def permalink!
12
+ replace(self.permalink)
13
+ end
14
+
15
+ alias :parameterize! :permalink!
16
+
17
+ end
@@ -0,0 +1,125 @@
1
+ # http://stackoverflow.com/questions/9556546/is-there-a-way-to-tell-psych-in-ruby-to-using-inline-mode
2
+ # https://gist.github.com/2023978
3
+
4
+ require 'psych'
5
+ require 'stringio'
6
+
7
+ # Public: A Psych extension to enable choosing output styles for specific
8
+ # objects.
9
+ #
10
+ # Thanks to Tenderlove for help in <http://stackoverflow.com/q/9640277/11687>
11
+ #
12
+ # Examples
13
+ #
14
+ # data = {
15
+ # response: { body: StyledYAML.literal(json_string), status: 200 },
16
+ # person: StyledYAML.inline({ 'name' => 'Stevie', 'age' => 12 }),
17
+ # array: StyledYAML.inline(%w[ apples bananas oranges ])
18
+ # }
19
+ #
20
+ # StyledYAML.dump data, $stdout
21
+ #
22
+ module StyledYAML
23
+ # Tag strings to be output using literal style
24
+ def self.literal obj
25
+ obj.extend LiteralScalar
26
+ return obj
27
+ end
28
+
29
+ # http://www.yaml.org/spec/1.2/spec.html#id2795688
30
+ module LiteralScalar
31
+ def yaml_style() Psych::Nodes::Scalar::LITERAL end
32
+ end
33
+
34
+ # Tag Hashes or Arrays to be output all on one line
35
+ def self.inline obj
36
+ case obj
37
+ when Hash then obj.extend FlowMapping
38
+ when Array then obj.extend FlowSequence
39
+ else
40
+ warn "#{self}: unrecognized type to inline (#{obj.class.name})"
41
+ end
42
+ return obj
43
+ end
44
+
45
+ # http://www.yaml.org/spec/1.2/spec.html#id2790832
46
+ module FlowMapping
47
+ def yaml_style() Psych::Nodes::Mapping::FLOW end
48
+ end
49
+
50
+ # http://www.yaml.org/spec/1.2/spec.html#id2790320
51
+ module FlowSequence
52
+ def yaml_style() Psych::Nodes::Sequence::FLOW end
53
+ end
54
+
55
+ # Custom tree builder class to recognize scalars tagged with `yaml_style`
56
+ class TreeBuilder < Psych::TreeBuilder
57
+ attr_writer :next_sequence_or_mapping_style
58
+
59
+ def initialize(*args)
60
+ super
61
+ @next_sequence_or_mapping_style = nil
62
+ end
63
+
64
+ def next_sequence_or_mapping_style default_style
65
+ style = @next_sequence_or_mapping_style || default_style
66
+ @next_sequence_or_mapping_style = nil
67
+ style
68
+ end
69
+
70
+ def scalar value, anchor, tag, plain, quoted, style
71
+ if style_any?(style) and value.respond_to?(:yaml_style) and style = value.yaml_style
72
+ if style_literal? style
73
+ plain = false
74
+ quoted = true
75
+ end
76
+ end
77
+ super
78
+ end
79
+
80
+ def style_any?(style) Psych::Nodes::Scalar::ANY == style end
81
+
82
+ def style_literal?(style) Psych::Nodes::Scalar::LITERAL == style end
83
+
84
+ %w[sequence mapping].each do |type|
85
+ class_eval <<-RUBY
86
+ def start_#{type}(anchor, tag, implicit, style)
87
+ style = next_sequence_or_mapping_style(style)
88
+ super
89
+ end
90
+ RUBY
91
+ end
92
+ end
93
+
94
+ # Custom tree class to handle Hashes and Arrays tagged with `yaml_style`
95
+ class YAMLTree < Psych::Visitors::YAMLTree
96
+ %w[Hash Array Psych_Set Psych_Omap].each do |klass|
97
+ class_eval <<-RUBY
98
+ def visit_#{klass} o
99
+ if o.respond_to? :yaml_style
100
+ @emitter.next_sequence_or_mapping_style = o.yaml_style
101
+ end
102
+ super
103
+ end
104
+ RUBY
105
+ end
106
+ end
107
+
108
+ # A Psych.dump alternative that uses the custom TreeBuilder
109
+ def self.dump obj, io = nil, options = {}
110
+ real_io = io || StringIO.new(''.encode('utf-8'))
111
+ visitor = YAMLTree.new(options, TreeBuilder.new)
112
+ visitor << obj
113
+ ast = visitor.tree
114
+
115
+ begin
116
+ ast.yaml real_io
117
+ rescue
118
+ # The `yaml` method was introduced in later versions, so fall back to
119
+ # constructing a visitor
120
+ Psych::Visitors::Emitter.new(real_io).accept ast
121
+ end
122
+
123
+ io ? io : real_io.string
124
+ end
125
+ end
@@ -0,0 +1,8 @@
1
+ # encoding: utf-8
2
+ module Locomotive
3
+ module Mounter #:nodoc
4
+
5
+ VERSION = '1.0.0.alpha1'
6
+
7
+ end
8
+ end