forge 0.0.1

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 (57) hide show
  1. data/.document +5 -0
  2. data/.gitmodules +3 -0
  3. data/.rspec +1 -0
  4. data/Gemfile +24 -0
  5. data/Gemfile.lock +81 -0
  6. data/LICENSE +20 -0
  7. data/README.md +24 -0
  8. data/Rakefile +53 -0
  9. data/VERSION +1 -0
  10. data/bin/forge +12 -0
  11. data/features/create.feature +34 -0
  12. data/features/link.feature +14 -0
  13. data/features/step_definitions/forge_steps.rb +38 -0
  14. data/features/support/env.rb +17 -0
  15. data/forge.gemspec +135 -0
  16. data/layouts/config/config.json.erb +13 -0
  17. data/layouts/config/stylesheet_header.erb +11 -0
  18. data/layouts/default/functions/functions.php.erb +21 -0
  19. data/layouts/default/stylesheets/_reset.scss +5 -0
  20. data/layouts/default/stylesheets/_typography.scss +5 -0
  21. data/layouts/default/stylesheets/style.css.scss.erb +28 -0
  22. data/layouts/default/templates/404.php.erb +10 -0
  23. data/layouts/default/templates/archive.php.erb +11 -0
  24. data/layouts/default/templates/attachment.php.erb +34 -0
  25. data/layouts/default/templates/comments.php +2 -0
  26. data/layouts/default/templates/footer.php +9 -0
  27. data/layouts/default/templates/header.php.erb +30 -0
  28. data/layouts/default/templates/index.php +6 -0
  29. data/layouts/default/templates/page.php +18 -0
  30. data/layouts/default/templates/partials/loop.php.erb +30 -0
  31. data/layouts/default/templates/search.php.erb +14 -0
  32. data/layouts/default/templates/sidebar.php +9 -0
  33. data/layouts/default/templates/single.php.erb +32 -0
  34. data/layouts/lib/forge-settings/README.md +43 -0
  35. data/layouts/lib/forge-settings/classes/settings.php +11 -0
  36. data/layouts/lib/forge-settings/classes/settings/collection.php +190 -0
  37. data/layouts/lib/forge-settings/classes/settings/option.php +125 -0
  38. data/layouts/lib/forge-settings/classes/settings/option/select.php +30 -0
  39. data/layouts/lib/forge-settings/classes/settings/option/text.php +15 -0
  40. data/layouts/lib/forge-settings/classes/settings/section.php +56 -0
  41. data/lib/forge.rb +11 -0
  42. data/lib/forge/builder.rb +165 -0
  43. data/lib/forge/cli.rb +86 -0
  44. data/lib/forge/config.rb +63 -0
  45. data/lib/forge/error.rb +8 -0
  46. data/lib/forge/generator.rb +128 -0
  47. data/lib/forge/guard.rb +57 -0
  48. data/lib/forge/project.rb +91 -0
  49. data/lib/forge/version.rb +3 -0
  50. data/lib/guard/forge/assets.rb +31 -0
  51. data/lib/guard/forge/config.rb +31 -0
  52. data/lib/guard/forge/functions.rb +31 -0
  53. data/lib/guard/forge/templates.rb +28 -0
  54. data/spec/lib/forge/config_spec.rb +79 -0
  55. data/spec/lib/forge/project_spec.rb +34 -0
  56. data/spec/spec_helper.rb +13 -0
  57. metadata +263 -0
@@ -0,0 +1,63 @@
1
+ require 'json'
2
+
3
+ module Forge
4
+ # Reads/Writes a configuration file in the user's home directory
5
+ #
6
+ class Config
7
+
8
+ @config
9
+
10
+ attr_accessor :config
11
+
12
+ def initialize()
13
+ @config = {
14
+ :theme => {
15
+ :author => nil,
16
+ :author_url => nil,
17
+ },
18
+ :links => []
19
+ }
20
+ end
21
+
22
+ # Provides access to the config using the Hash square brackets
23
+ def [](var)
24
+ @config[var]
25
+ end
26
+
27
+ # Allows modifying variables through hash square brackets
28
+ def []=(var, value)
29
+ @config[var] = value
30
+ end
31
+
32
+ # Returns the path to the user's configuration file
33
+ def config_file
34
+ @config_file ||= File.expand_path(File.join('~', '.forge', 'config.yml'))
35
+ end
36
+
37
+ # Writes the configuration file
38
+ def write(options={})
39
+ # If we're unit testing then it helps to use a
40
+ # StringIO object instead of a file buffer
41
+ io = options[:io] || File.open(self.config_file, 'w')
42
+
43
+ io.write JSON.generate(@config)
44
+
45
+ io.close
46
+
47
+ self
48
+ end
49
+
50
+ # Loads config declarations in user's home dir
51
+ #
52
+ # If file does not exist then it will be created
53
+ def read
54
+ return write unless File.exists?(self.config_file)
55
+
56
+ data = File.open(self.config_file).read
57
+
58
+ @config = data.empty? ? {} : JSON.parse(data)
59
+
60
+ self
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,8 @@
1
+ module Forge
2
+ class Error < StandardError
3
+ end
4
+
5
+ # Raised when the link source could not be found
6
+ class LinkSourceDirNotFound < Error
7
+ end
8
+ end
@@ -0,0 +1,128 @@
1
+
2
+ module Forge
3
+ class Generator
4
+ class << self
5
+ def run(project, layout='default')
6
+ generator = self.new(project, layout)
7
+ generator.run
8
+ end
9
+ end
10
+
11
+ def initialize(project, layout='default')
12
+ @project = project
13
+ @task = project.task
14
+ @layout = layout
15
+ end
16
+
17
+ def create_structure
18
+ # Create the build directory for Forge output
19
+ @task.empty_directory @project.build_path
20
+
21
+ source_paths = [
22
+ ['assets', 'images'],
23
+ ['assets', 'javascripts'],
24
+ ['assets', 'stylesheets'],
25
+
26
+ ['functions'],
27
+
28
+ ['includes'],
29
+
30
+ ['templates', 'pages'],
31
+ ['templates', 'partials'],
32
+ ]
33
+
34
+ # Build out Forge structure in the source directory
35
+ source_paths.each do |path|
36
+ @task.empty_directory File.join(@project.source_path, path)
37
+ end
38
+
39
+ self
40
+ end
41
+
42
+ def copy_stylesheets
43
+ source = File.expand_path(File.join(self.layout_path, 'stylesheets'))
44
+ target = File.expand_path(File.join(@project.assets_path, 'stylesheets'))
45
+
46
+ render_directory(source, target)
47
+
48
+ self
49
+ end
50
+
51
+ def copy_templates
52
+ source = File.expand_path(File.join(self.layout_path, 'templates'))
53
+ target = File.expand_path(File.join(@project.source_path, 'templates'))
54
+
55
+ render_directory(source, target)
56
+
57
+ self
58
+ end
59
+
60
+ def copy_settings_library
61
+ settings_path = @task.find_in_source_paths(File.join('lib', 'forge-settings', 'classes'))
62
+
63
+ source = File.expand_path(settings_path)
64
+ target = File.expand_path(File.join(@project.includes_path, 'forge-settings', '.'))
65
+
66
+ @task.directory(source, target)
67
+ end
68
+
69
+ def copy_functions
70
+ source = File.expand_path(File.join(self.layout_path, 'functions', 'functions.php.erb'))
71
+ target = File.expand_path(File.join(@project.source_path, 'functions', 'functions.php'))
72
+
73
+ write_template(source, target)
74
+ end
75
+
76
+ def layout_path
77
+ @layout_path ||= File.join(Forge::ROOT, 'layouts', @layout)
78
+ end
79
+
80
+ def run
81
+ write_config
82
+ create_structure
83
+ copy_stylesheets
84
+ copy_templates
85
+ copy_functions
86
+ copy_settings_library
87
+ return self
88
+ end
89
+
90
+ def write_config
91
+ write_template(['config', 'config.json.erb'], @project.config_file)
92
+
93
+ self
94
+ end
95
+
96
+ def write_template(source, target)
97
+ source = File.join(source)
98
+ template = File.expand_path(@task.find_in_source_paths((source)))
99
+ target = File.expand_path(File.join(target))
100
+
101
+ @task.create_file target do
102
+ @project.parse_erb(template)
103
+ end
104
+ end
105
+
106
+ protected
107
+ def render_directory(source, target)
108
+ Dir.glob("#{source}/**/*") do |file|
109
+ unless File.directory?(file)
110
+ source_file = file.gsub(source, '')
111
+ target_file = File.join(target, source_file)
112
+
113
+ if source_file.end_with? ".erb"
114
+ target_file = target_file.slice(0..-5)
115
+
116
+ content = @project.parse_erb(file)
117
+ else
118
+ content = File.open(file).read
119
+ end
120
+
121
+ @task.create_file target_file do
122
+ content
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,57 @@
1
+ require 'guard'
2
+ require 'guard/guard'
3
+
4
+ module Forge
5
+ module Guard
6
+
7
+ class << self
8
+ attr_accessor :project, :task, :builder
9
+ end
10
+
11
+ def self.add_guard(&block)
12
+ @additional_guards ||= []
13
+ @additional_guards << block
14
+ end
15
+
16
+ def self.start(project, task, options={}, livereload={})
17
+ @project = project
18
+ @task = task
19
+ @builder = Builder.new(project)
20
+
21
+ options_hash = ""
22
+ options.each do |k,v|
23
+ options_hash << ", :#{k} => '#{v}'"
24
+ end
25
+
26
+ assets_path = @project.assets_path.gsub(/#{@project.root}\//, '')
27
+ source_path = @project.source_path.gsub(/#{@project.root}\//, '')
28
+ config_file = @project.config_file.gsub(/#{@project.root}\//, '')
29
+
30
+ guardfile_contents = %Q{
31
+ guard 'forgeconfig'#{options_hash} do
32
+ watch("#{config_file}")
33
+ end
34
+ guard 'forgeassets' do
35
+ watch(%r{#{assets_path}/javascripts/*})
36
+ watch(%r{#{assets_path}/stylesheets/*})
37
+ watch(%r{#{assets_path}/images/*})
38
+ end
39
+ guard 'forgetemplates' do
40
+ watch(%r{#{source_path}/templates/*})
41
+ watch(%r{#{source_path}/partials/*})
42
+ end
43
+ guard 'forgefunctions' do
44
+ watch(%r{#{source_path}/functions/*})
45
+ watch(%r{#{source_path}/includes/*})
46
+ end
47
+ }
48
+
49
+ (@additional_guards || []).each do |block|
50
+ result = block.call(options, livereload)
51
+ guardfile_contents << result unless result.nil?
52
+ end
53
+
54
+ ::Guard.start({ :guardfile_contents => guardfile_contents })
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,91 @@
1
+ require 'pathname'
2
+ require 'json'
3
+
4
+ module Forge
5
+ class Project
6
+ class << self
7
+ def create(root, config, task)
8
+ root = File.expand_path(root)
9
+
10
+ project = self.new(root, task, config)
11
+ Generator.run(project)
12
+
13
+ project
14
+ end
15
+ end
16
+
17
+ attr_accessor :root, :config, :task
18
+
19
+ def initialize(root, task, config={})
20
+ @root = File.expand_path(root)
21
+ @config = config || {}
22
+ @task = task
23
+
24
+ self.load_config if @config.empty?
25
+ end
26
+
27
+ def assets_path
28
+ @assets_path ||= File.join(self.source_path, 'assets')
29
+ end
30
+
31
+ def build_path
32
+ File.join(self.root, '.forge', 'build')
33
+ end
34
+
35
+ def source_path
36
+ File.join(self.root, 'source')
37
+ end
38
+
39
+ def package_path
40
+ File.join(self.root, 'package')
41
+ end
42
+
43
+ def templates_path
44
+ File.join(self.source_path, 'templates')
45
+ end
46
+
47
+ def functions_path
48
+ File.join(self.source_path, 'functions')
49
+ end
50
+
51
+ def includes_path
52
+ File.join(self.source_path, 'includes')
53
+ end
54
+
55
+ def config_file
56
+ @config_file ||= File.join(self.root, 'config.json')
57
+ end
58
+
59
+ # Create a symlink from source to the project build dir
60
+ def link(source)
61
+ source = File.expand_path(source)
62
+
63
+ unless File.directory?(File.dirname(source))
64
+ raise Forge::LinkSourceDirNotFound
65
+ end
66
+
67
+ @task.link_file build_path, source
68
+ end
69
+
70
+ def theme_id
71
+ File.basename(self.root).gsub(/\W/, '_')
72
+ end
73
+
74
+ def load_config
75
+ unless File.exists?(self.config_file)
76
+ raise Error, "Could not find the config file, are you sure you're in a
77
+ forge project directory?"
78
+ end
79
+
80
+ self.config = JSON.parse File.open(config_file).read
81
+ end
82
+
83
+ def get_binding
84
+ binding
85
+ end
86
+
87
+ def parse_erb(file)
88
+ ERB.new(::File.binread(file), nil, '-', '@output_buffer').result(binding)
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,3 @@
1
+ module Forge
2
+ VERSION = "0.1"
3
+ end
@@ -0,0 +1,31 @@
1
+ require 'guard'
2
+ require 'guard/guard'
3
+
4
+ module Guard
5
+ class ForgeAssets < ::Guard::Guard
6
+
7
+ def initialize(watchers=[], options={})
8
+ super
9
+ end
10
+
11
+ def start
12
+ UI.info "Building all assets"
13
+ ::Forge::Guard.builder.build_assets
14
+ end
15
+
16
+ # Called on Ctrl-\ signal
17
+ # This method should be principally used for long action like running all specs/tests/...
18
+ def run_all
19
+ UI.info "Rebuilding all assets"
20
+ ::Forge::Guard.builder.clean_images
21
+ ::Forge::Guard.builder.build_assets
22
+ end
23
+
24
+ # Called on file(s) modifications
25
+ def run_on_change(paths)
26
+ UI.info "Assets have changed, rebuilding..."
27
+ ::Forge::Guard.builder.clean_images
28
+ ::Forge::Guard.builder.build_assets
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ require 'guard'
2
+ require 'guard/guard'
3
+
4
+ module Guard
5
+ class ForgeConfig < ::Guard::Guard
6
+ def initialize(watchers=[], options={})
7
+ super
8
+ end
9
+
10
+ # Called on Ctrl-Z signal
11
+ # This method should be mainly used for "reload" (really!) actions like reloading passenger/spork/bundler/...
12
+ def reload
13
+ UI.info "Reloading project config"
14
+ ::Forge::Guard.project.load_config
15
+ end
16
+
17
+ # Called on Ctrl-\ signal
18
+ # This method should be principally used for long action like running all specs/tests/...
19
+ def run_all
20
+ UI.info "Reloading project config"
21
+ ::Forge::Guard.project.load_config
22
+ true
23
+ end
24
+
25
+ # Called on file(s) modifications
26
+ def run_on_change(paths)
27
+ UI.info "Project config changed, reloading"
28
+ ::Forge::Guard.project.load_config
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ require 'guard'
2
+ require 'guard/guard'
3
+
4
+ module Guard
5
+ class ForgeFunctions < ::Guard::Guard
6
+ def initialize(watchers=[], options={})
7
+ super
8
+ end
9
+
10
+ def start
11
+ UI.info "Copying functions over"
12
+ ::Forge::Guard.builder.copy_functions
13
+ ::Forge::Guard.builder.copy_includes
14
+ end
15
+
16
+ def run_all
17
+ UI.info "Rebuilding all functions"
18
+ ::Forge::Guard.builder.copy_functions
19
+ ::Forge::Guard.builder.clean_includes
20
+ ::Forge::Guard.builder.copy_includes
21
+ end
22
+
23
+ # Called on file(s) modifications
24
+ def run_on_change(paths)
25
+ UI.info "Functions have changed, copying over"
26
+ ::Forge::Guard.builder.copy_functions
27
+ ::Forge::Guard.builder.clean_includes
28
+ ::Forge::Guard.builder.copy_includes
29
+ end
30
+ end
31
+ end