├── Rails ├── blog-app │ ├── log │ │ └── .keep │ ├── app │ │ ├── mailers │ │ │ └── .keep │ │ ├── models │ │ │ ├── .keep │ │ │ ├── concerns │ │ │ │ └── .keep │ │ │ └── post.rb │ │ ├── assets │ │ │ ├── images │ │ │ │ └── .keep │ │ │ ├── stylesheets │ │ │ │ ├── posts.scss │ │ │ │ ├── application.css │ │ │ │ └── scaffolds.scss │ │ │ └── javascripts │ │ │ │ ├── posts.coffee │ │ │ │ └── application.js │ │ ├── controllers │ │ │ ├── concerns │ │ │ │ └── .keep │ │ │ ├── application_controller.rb │ │ │ └── posts_controller.rb │ │ ├── helpers │ │ │ ├── posts_helper.rb │ │ │ └── application_helper.rb │ │ └── views │ │ │ ├── posts │ │ │ ├── show.json.jbuilder │ │ │ ├── new.html.erb │ │ │ ├── edit.html.erb │ │ │ ├── index.json.jbuilder │ │ │ ├── show.html.erb │ │ │ ├── _form.html.erb │ │ │ └── index.html.erb │ │ │ └── layouts │ │ │ └── application.html.erb │ ├── lib │ │ ├── assets │ │ │ └── .keep │ │ └── tasks │ │ │ └── .keep │ ├── public │ │ ├── favicon.ico │ │ ├── robots.txt │ │ ├── 500.html │ │ ├── 422.html │ │ └── 404.html │ ├── test │ │ ├── helpers │ │ │ └── .keep │ │ ├── mailers │ │ │ └── .keep │ │ ├── models │ │ │ ├── .keep │ │ │ └── post_test.rb │ │ ├── controllers │ │ │ ├── .keep │ │ │ └── posts_controller_test.rb │ │ ├── fixtures │ │ │ ├── .keep │ │ │ └── posts.yml │ │ ├── integration │ │ │ └── .keep │ │ └── test_helper.rb │ ├── vendor │ │ └── assets │ │ │ ├── javascripts │ │ │ └── .keep │ │ │ └── stylesheets │ │ │ └── .keep │ ├── bin │ │ ├── bundle │ │ ├── rake │ │ ├── rails │ │ ├── spring │ │ └── setup │ ├── config │ │ ├── boot.rb │ │ ├── initializers │ │ │ ├── cookies_serializer.rb │ │ │ ├── session_store.rb │ │ │ ├── mime_types.rb │ │ │ ├── filter_parameter_logging.rb │ │ │ ├── backtrace_silencers.rb │ │ │ ├── assets.rb │ │ │ ├── wrap_parameters.rb │ │ │ └── inflections.rb │ │ ├── environment.rb │ │ ├── database.yml │ │ ├── locales │ │ │ └── en.yml │ │ ├── secrets.yml │ │ ├── application.rb │ │ ├── environments │ │ │ ├── development.rb │ │ │ ├── test.rb │ │ │ └── production.rb │ │ └── routes.rb │ ├── config.ru │ ├── db │ │ ├── migrate │ │ │ └── 20150930193323_create_posts.rb │ │ └── seeds.rb │ ├── Rakefile │ ├── .gitignore │ ├── README.rdoc │ ├── Gemfile │ └── Gemfile.lock └── README.md ├── Android ├── Sample-Android │ ├── .idea │ │ ├── .name │ │ ├── copyright │ │ │ └── profiles_settings.xml │ │ ├── encodings.xml │ │ ├── vcs.xml │ │ ├── modules.xml │ │ ├── runConfigurations.xml │ │ ├── compiler.xml │ │ ├── gradle.xml │ │ └── misc.xml │ ├── designpatterns │ │ ├── .gitignore │ │ ├── src │ │ │ ├── main │ │ │ │ ├── res │ │ │ │ │ ├── drawable │ │ │ │ │ │ ├── error.png │ │ │ │ │ │ ├── burger.png │ │ │ │ │ │ ├── chicken.png │ │ │ │ │ │ └── loading.png │ │ │ │ │ ├── values │ │ │ │ │ │ ├── strings.xml │ │ │ │ │ │ ├── colors.xml │ │ │ │ │ │ ├── dimens.xml │ │ │ │ │ │ └── styles.xml │ │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── values-v21 │ │ │ │ │ │ └── styles.xml │ │ │ │ │ ├── values-w820dp │ │ │ │ │ │ └── dimens.xml │ │ │ │ │ ├── menu │ │ │ │ │ │ └── menu_main.xml │ │ │ │ │ └── layout │ │ │ │ │ │ ├── content_main.xml │ │ │ │ │ │ ├── activity_main.xml │ │ │ │ │ │ └── restaurant_item.xml │ │ │ │ ├── java │ │ │ │ │ └── com │ │ │ │ │ │ └── metova │ │ │ │ │ │ └── designpatterns │ │ │ │ │ │ ├── data │ │ │ │ │ │ ├── RestaurantFactory.java │ │ │ │ │ │ ├── Restaurant.java │ │ │ │ │ │ ├── HotChicken.java │ │ │ │ │ │ ├── Burger.java │ │ │ │ │ │ └── DataManager.java │ │ │ │ │ │ └── ui │ │ │ │ │ │ ├── MainActivity.java │ │ │ │ │ │ ├── ViewHolder.java │ │ │ │ │ │ └── ListAdapter.java │ │ │ │ └── AndroidManifest.xml │ │ │ ├── test │ │ │ │ └── java │ │ │ │ │ └── com │ │ │ │ │ └── metova │ │ │ │ │ └── designpatterns │ │ │ │ │ └── ExampleUnitTest.java │ │ │ └── androidTest │ │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── metova │ │ │ │ └── designpatterns │ │ │ │ └── ApplicationTest.java │ │ ├── proguard-rules.pro │ │ ├── build.gradle │ │ └── designpatterns.iml │ ├── settings.gradle │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── .gitignore │ ├── build.gradle │ ├── gradle.properties │ ├── Sample-Android.iml │ ├── gradlew.bat │ └── gradlew └── README.md ├── iOS ├── README.md └── DesignPatternsSample │ ├── KIF_SCREENSHOTS │ └── .gitignore │ ├── Crashlytics.framework │ ├── run │ ├── submit │ ├── Crashlytics │ ├── Modules │ │ └── module.modulemap │ ├── Versions │ │ ├── A │ │ │ ├── Crashlytics │ │ │ ├── Resources │ │ │ │ └── Info.plist │ │ │ └── Headers │ │ │ │ └── Crashlytics.h │ │ └── Current │ │ │ ├── Crashlytics │ │ │ ├── Resources │ │ │ └── Info.plist │ │ │ └── Headers │ │ │ └── Crashlytics.h │ ├── Resources │ │ └── Info.plist │ └── Headers │ │ └── Crashlytics.h │ ├── Gemfile │ ├── DesignPatternsSample.xcodeproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── DesignPatternsSample.xccheckout │ └── xcshareddata │ │ └── xcschemes │ │ ├── Tests.xcscheme │ │ └── DesignPatternsSample.xcscheme │ ├── DesignPatternsSample │ ├── Constants.swift │ ├── Constants+WebPaths.swift │ ├── Location.swift │ ├── Restaurant.swift │ ├── DesignPatternsSample-Bridging-Header.h │ ├── Constants+WebKeys.swift │ ├── DDLogSwift.h │ ├── RestaurantCell.swift │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Info.plist │ ├── BuildEnvironment.h │ ├── ModelParser.swift │ ├── BuildEnvironment.m │ ├── WebService.swift │ ├── Base.lproj │ │ └── LaunchScreen.xib │ ├── AppDelegate.swift │ ├── DDLogSwift.m │ ├── RestaurantCell.xib │ └── Main.storyboard │ ├── DesignPatternsSample.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── DesignPatternsSample.xccheckout │ ├── .gitignore │ ├── Podfile │ ├── Tests │ ├── HomeViewControllerTests.swift │ ├── Info.plist │ └── LoginViewControllerTests.swift │ ├── UITests │ ├── Info.plist │ └── UITests.swift │ └── Podfile.lock └── README.md /Rails/blog-app/log/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Rails/blog-app/app/mailers/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Rails/blog-app/app/models/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Rails/blog-app/lib/assets/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Rails/blog-app/lib/tasks/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Rails/blog-app/public/favicon.ico: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Rails/blog-app/test/helpers/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Rails/blog-app/test/mailers/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Rails/blog-app/test/models/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Rails/blog-app/app/assets/images/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Rails/blog-app/test/controllers/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Rails/blog-app/test/fixtures/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Rails/blog-app/test/integration/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Rails/blog-app/app/models/concerns/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Android/Sample-Android/.idea/.name: -------------------------------------------------------------------------------- 1 | Sample-Android -------------------------------------------------------------------------------- /Rails/blog-app/app/controllers/concerns/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Rails/blog-app/vendor/assets/javascripts/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Rails/blog-app/vendor/assets/stylesheets/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /iOS/README.md: -------------------------------------------------------------------------------- 1 | ### iOS Design Pattern Samples ### -------------------------------------------------------------------------------- /Rails/README.md: -------------------------------------------------------------------------------- 1 | ### Rails Design Pattern Samples ### -------------------------------------------------------------------------------- /Android/README.md: -------------------------------------------------------------------------------- 1 | ### Android Design Pattern Samples ### -------------------------------------------------------------------------------- /Android/Sample-Android/designpatterns/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /Android/Sample-Android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':designpatterns' 2 | -------------------------------------------------------------------------------- /Rails/blog-app/app/helpers/posts_helper.rb: -------------------------------------------------------------------------------- 1 | module PostsHelper 2 | end 3 | -------------------------------------------------------------------------------- /Rails/blog-app/app/models/post.rb: -------------------------------------------------------------------------------- 1 | class Post < ActiveRecord::Base 2 | end 3 | -------------------------------------------------------------------------------- /Rails/blog-app/app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | end 3 | -------------------------------------------------------------------------------- /Rails/blog-app/app/views/posts/show.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.extract! @post, :id, :title, :body, :created_at, :updated_at 2 | -------------------------------------------------------------------------------- /Rails/blog-app/app/views/posts/new.html.erb: -------------------------------------------------------------------------------- 1 |

New Post

2 | 3 | <%= render 'form' %> 4 | 5 | <%= link_to 'Back', posts_path %> 6 | -------------------------------------------------------------------------------- /iOS/DesignPatternsSample/KIF_SCREENSHOTS/.gitignore: -------------------------------------------------------------------------------- 1 | gnore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore 5 | -------------------------------------------------------------------------------- /Android/Sample-Android/.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /Rails/blog-app/bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 3 | load Gem.bin_path('bundler', 'bundle') 4 | -------------------------------------------------------------------------------- /iOS/DesignPatternsSample/Crashlytics.framework/run: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metova/design-patterns-sample/HEAD/iOS/DesignPatternsSample/Crashlytics.framework/run -------------------------------------------------------------------------------- /Rails/blog-app/config/boot.rb: -------------------------------------------------------------------------------- 1 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 2 | 3 | require 'bundler/setup' # Set up gems listed in the Gemfile. 4 | -------------------------------------------------------------------------------- /iOS/DesignPatternsSample/Crashlytics.framework/submit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metova/design-patterns-sample/HEAD/iOS/DesignPatternsSample/Crashlytics.framework/submit -------------------------------------------------------------------------------- /iOS/DesignPatternsSample/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | gem 'cocoapods', '>=0.35.0' 3 | gem 'ocunit2junit', git: 'http://github.com/Sarkazein/OCUnit2JUnit.git' -------------------------------------------------------------------------------- /Android/Sample-Android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metova/design-patterns-sample/HEAD/Android/Sample-Android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /Rails/blog-app/app/views/posts/edit.html.erb: -------------------------------------------------------------------------------- 1 |

Editing Post

2 | 3 | <%= render 'form' %> 4 | 5 | <%= link_to 'Show', @post %> | 6 | <%= link_to 'Back', posts_path %> 7 | -------------------------------------------------------------------------------- /Rails/blog-app/app/views/posts/index.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.array!(@posts) do |post| 2 | json.extract! post, :id, :title, :body 3 | json.url post_url(post, format: :json) 4 | end 5 | -------------------------------------------------------------------------------- /iOS/DesignPatternsSample/Crashlytics.framework/Crashlytics: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metova/design-patterns-sample/HEAD/iOS/DesignPatternsSample/Crashlytics.framework/Crashlytics -------------------------------------------------------------------------------- /Rails/blog-app/test/models/post_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class PostTest < ActiveSupport::TestCase 4 | # test "the truth" do 5 | # assert true 6 | # end 7 | end 8 | -------------------------------------------------------------------------------- /Rails/blog-app/config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require ::File.expand_path('../config/environment', __FILE__) 4 | run Rails.application 5 | -------------------------------------------------------------------------------- /Rails/blog-app/config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Rails.application.config.action_dispatch.cookies_serializer = :json 4 | -------------------------------------------------------------------------------- /iOS/DesignPatternsSample/Crashlytics.framework/Modules/module.modulemap: -------------------------------------------------------------------------------- 1 | framework module Crashlytics { 2 | umbrella header "Crashlytics.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Android/Sample-Android/designpatterns/src/main/res/drawable/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metova/design-patterns-sample/HEAD/Android/Sample-Android/designpatterns/src/main/res/drawable/error.png -------------------------------------------------------------------------------- /Rails/blog-app/config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Rails.application.config.session_store :cookie_store, key: '_blog-app_session' 4 | -------------------------------------------------------------------------------- /iOS/DesignPatternsSample/Crashlytics.framework/Versions/A/Crashlytics: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metova/design-patterns-sample/HEAD/iOS/DesignPatternsSample/Crashlytics.framework/Versions/A/Crashlytics -------------------------------------------------------------------------------- /Android/Sample-Android/designpatterns/src/main/res/drawable/burger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metova/design-patterns-sample/HEAD/Android/Sample-Android/designpatterns/src/main/res/drawable/burger.png -------------------------------------------------------------------------------- /Android/Sample-Android/designpatterns/src/main/res/drawable/chicken.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metova/design-patterns-sample/HEAD/Android/Sample-Android/designpatterns/src/main/res/drawable/chicken.png -------------------------------------------------------------------------------- /Android/Sample-Android/designpatterns/src/main/res/drawable/loading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metova/design-patterns-sample/HEAD/Android/Sample-Android/designpatterns/src/main/res/drawable/loading.png -------------------------------------------------------------------------------- /Rails/blog-app/config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require File.expand_path('../application', __FILE__) 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /Android/Sample-Android/designpatterns/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | DesignPatterns 3 | Settings 4 | 5 | -------------------------------------------------------------------------------- /iOS/DesignPatternsSample/Crashlytics.framework/Versions/Current/Crashlytics: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metova/design-patterns-sample/HEAD/iOS/DesignPatternsSample/Crashlytics.framework/Versions/Current/Crashlytics -------------------------------------------------------------------------------- /Android/Sample-Android/.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Android/Sample-Android/designpatterns/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metova/design-patterns-sample/HEAD/Android/Sample-Android/designpatterns/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /Android/Sample-Android/designpatterns/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metova/design-patterns-sample/HEAD/Android/Sample-Android/designpatterns/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /Android/Sample-Android/designpatterns/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metova/design-patterns-sample/HEAD/Android/Sample-Android/designpatterns/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /Rails/blog-app/bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | begin 3 | load File.expand_path("../spring", __FILE__) 4 | rescue LoadError 5 | end 6 | require_relative '../config/boot' 7 | require 'rake' 8 | Rake.application.run 9 | -------------------------------------------------------------------------------- /Rails/blog-app/config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | -------------------------------------------------------------------------------- /Android/Sample-Android/designpatterns/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metova/design-patterns-sample/HEAD/Android/Sample-Android/designpatterns/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /Android/Sample-Android/designpatterns/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metova/design-patterns-sample/HEAD/Android/Sample-Android/designpatterns/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /Android/Sample-Android/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | /.idea/workspace.xml 4 | /.idea/libraries 5 | .DS_Store 6 | /build 7 | /captures 8 | 9 | # IntelliJ files 10 | /.idea 11 | *.iml 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Rails/blog-app/app/assets/stylesheets/posts.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the Posts controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | -------------------------------------------------------------------------------- /Rails/blog-app/test/fixtures/posts.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html 2 | 3 | one: 4 | title: MyString 5 | body: MyText 6 | 7 | two: 8 | title: MyString 9 | body: MyText 10 | -------------------------------------------------------------------------------- /Rails/blog-app/public/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file 2 | # 3 | # To ban all spiders from the entire site uncomment the next two lines: 4 | # User-agent: * 5 | # Disallow: / 6 | -------------------------------------------------------------------------------- /Rails/blog-app/app/assets/javascripts/posts.coffee: -------------------------------------------------------------------------------- 1 | # Place all the behaviors and hooks related to the matching controller here. 2 | # All this logic will automatically be available in application.js. 3 | # You can use CoffeeScript in this file: http://coffeescript.org/ 4 | -------------------------------------------------------------------------------- /Rails/blog-app/config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure sensitive parameters which will be filtered from the log file. 4 | Rails.application.config.filter_parameters += [:password] 5 | -------------------------------------------------------------------------------- /Rails/blog-app/bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | begin 3 | load File.expand_path("../spring", __FILE__) 4 | rescue LoadError 5 | end 6 | APP_PATH = File.expand_path('../../config/application', __FILE__) 7 | require_relative '../config/boot' 8 | require 'rails/commands' 9 | -------------------------------------------------------------------------------- /Android/Sample-Android/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Rails/blog-app/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | # Prevent CSRF attacks by raising an exception. 3 | # For APIs, you may want to use :null_session instead. 4 | protect_from_forgery with: :exception 5 | end 6 | -------------------------------------------------------------------------------- /Rails/blog-app/db/migrate/20150930193323_create_posts.rb: -------------------------------------------------------------------------------- 1 | class CreatePosts < ActiveRecord::Migration 2 | def change 3 | create_table :posts do |t| 4 | t.string :title 5 | t.text :body 6 | 7 | t.timestamps null: false 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /iOS/DesignPatternsSample/DesignPatternsSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Rails/blog-app/Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require File.expand_path('../config/application', __FILE__) 5 | 6 | Rails.application.load_tasks 7 | -------------------------------------------------------------------------------- /Android/Sample-Android/designpatterns/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /Android/Sample-Android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Sep 17 10:31:31 CDT 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip 7 | -------------------------------------------------------------------------------- /Rails/blog-app/app/views/posts/show.html.erb: -------------------------------------------------------------------------------- 1 |

<%= notice %>

2 | 3 |

4 | Title: 5 | <%= @post.title %> 6 |

7 | 8 |

9 | Body: 10 | <%= @post.body %> 11 |

12 | 13 | <%= link_to 'Edit', edit_post_path(@post) %> | 14 | <%= link_to 'Back', posts_path %> 15 | -------------------------------------------------------------------------------- /iOS/DesignPatternsSample/DesignPatternsSample/Constants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Constants.swift 3 | // DesignPatternsSample 4 | // 5 | // Created by Nick Griffith on 8/10/15. 6 | // Copyright (c) 2015 Metova. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct Constants { 12 | struct Web { 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /iOS/DesignPatternsSample/DesignPatternsSample.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Android/Sample-Android/designpatterns/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 180dp 6 | 16dp 7 | 8 | -------------------------------------------------------------------------------- /Rails/blog-app/db/seeds.rb: -------------------------------------------------------------------------------- 1 | # This file should contain all the record creation needed to seed the database with its default values. 2 | # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). 3 | # 4 | # Examples: 5 | # 6 | # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) 7 | # Mayor.create(name: 'Emanuel', city: cities.first) 8 | -------------------------------------------------------------------------------- /Rails/blog-app/test/test_helper.rb: -------------------------------------------------------------------------------- 1 | ENV['RAILS_ENV'] ||= 'test' 2 | require File.expand_path('../../config/environment', __FILE__) 3 | require 'rails/test_help' 4 | 5 | class ActiveSupport::TestCase 6 | # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. 7 | fixtures :all 8 | 9 | # Add more helper methods to be used by all tests here... 10 | end 11 | -------------------------------------------------------------------------------- /iOS/DesignPatternsSample/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore Pods directory (it's autogenerated from CocoaPods tool) 2 | Pods/ 3 | 4 | # Ignore tmp directory (where unit test results are written to) 5 | tmp/ 6 | 7 | # Ignore build directory (where Xcode places it's build files when ran from the command line) 8 | build/ 9 | 10 | # Ignore lcov Files 11 | *.info 12 | 13 | # Ignore xcuserdata 14 | xcuserdata/ -------------------------------------------------------------------------------- /Rails/blog-app/app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | BlogApp 5 | <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %> 6 | <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %> 7 | <%= csrf_meta_tags %> 8 | 9 | 10 | 11 | <%= yield %> 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /iOS/DesignPatternsSample/DesignPatternsSample/Constants+WebPaths.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WebConstants.swift 3 | // DesignPatternsSample 4 | // 5 | // Created by Metova on ___DATE___. 6 | // Copyright (c) 2015 Metova. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension Constants.Web { 12 | struct Paths { 13 | static let Login = "/login" 14 | static let Users = "/Users" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Android/Sample-Android/designpatterns/src/main/res/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 10 | 14 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

We're sorry, but something went wrong.

62 |
63 |

If you are the application owner check the logs for more information.

64 |
65 | 66 | 67 | -------------------------------------------------------------------------------- /Rails/blog-app/config/environments/development.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # In the development environment your application's code is reloaded on 5 | # every request. This slows down response time but is perfect for development 6 | # since you don't have to restart the web server when you make code changes. 7 | config.cache_classes = false 8 | 9 | # Do not eager load code on boot. 10 | config.eager_load = false 11 | 12 | # Show full error reports and disable caching. 13 | config.consider_all_requests_local = true 14 | config.action_controller.perform_caching = false 15 | 16 | # Don't care if the mailer can't send. 17 | config.action_mailer.raise_delivery_errors = false 18 | 19 | # Print deprecation notices to the Rails logger. 20 | config.active_support.deprecation = :log 21 | 22 | # Raise an error on page load if there are pending migrations. 23 | config.active_record.migration_error = :page_load 24 | 25 | # Debug mode disables concatenation and preprocessing of assets. 26 | # This option may cause significant delays in view rendering with a large 27 | # number of complex assets. 28 | config.assets.debug = true 29 | 30 | # Asset digests allow you to set far-future HTTP expiration dates on all assets, 31 | # yet still be able to expire them through the digest params. 32 | config.assets.digest = true 33 | 34 | # Adds additional error checking when serving assets at runtime. 35 | # Checks for improperly declared sprockets dependencies. 36 | # Raises helpful error messages. 37 | config.assets.raise_runtime_errors = true 38 | 39 | # Raises error for missing translations 40 | # config.action_view.raise_on_missing_translations = true 41 | end 42 | -------------------------------------------------------------------------------- /iOS/DesignPatternsSample/DesignPatternsSample.xcworkspace/xcshareddata/DesignPatternsSample.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | D1B1FCC7-04CC-4DBE-979F-128837B1F5EC 9 | IDESourceControlProjectName 10 | DesignPatternsSample 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 07DF3EAD1575E82863958A37D05694A2E23BB32A 14 | ssh://bitbucket.org/metova/metova-ios-archetype.git 15 | 16 | IDESourceControlProjectPath 17 | DesignPatternsSample/DesignPatternsSample.xcworkspace 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 07DF3EAD1575E82863958A37D05694A2E23BB32A 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | ssh://bitbucket.org/metova/metova-ios-archetype.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | 07DF3EAD1575E82863958A37D05694A2E23BB32A 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 07DF3EAD1575E82863958A37D05694A2E23BB32A 36 | IDESourceControlWCCName 37 | metova-ios-archetype 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /iOS/DesignPatternsSample/DesignPatternsSample.xcodeproj/project.xcworkspace/xcshareddata/DesignPatternsSample.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 079DC0ED-FCAA-436A-A1C3-3E32182443A7 9 | IDESourceControlProjectName 10 | project 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 07DF3EAD1575E82863958A37D05694A2E23BB32A 14 | https://bitbucket.org/metova/metova-ios-archetype.git 15 | 16 | IDESourceControlProjectPath 17 | DesignPatternsSample/DesignPatternsSample.xcodeproj/project.xcworkspace 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 07DF3EAD1575E82863958A37D05694A2E23BB32A 21 | ../../.. 22 | 23 | IDESourceControlProjectURL 24 | https://bitbucket.org/metova/metova-ios-archetype.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | 07DF3EAD1575E82863958A37D05694A2E23BB32A 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 07DF3EAD1575E82863958A37D05694A2E23BB32A 36 | IDESourceControlWCCName 37 | metova-ios-archetype 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Rails/blog-app/public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The change you wanted was rejected.

62 |

Maybe you tried to change something you didn't have access to.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /iOS/DesignPatternsSample/DesignPatternsSample/BuildEnvironment.h: -------------------------------------------------------------------------------- 1 | // 2 | // BuildEnvironment.h 3 | // DesignPatternsSample 4 | // 5 | // Created by Metova on ___DATE___. 6 | // Copyright (c) 2015 Metova. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #define BUILD_ENVIRONMENT_DEVELOPMENT 1 12 | #define BUILD_ENVIRONMENT_STAGING 2 13 | #define BUILD_ENVIRONMENT_PRODUCTION 3 14 | 15 | FOUNDATION_EXPORT NSString *const kBaseURL; 16 | 17 | @interface BuildEnvironment : NSObject 18 | 19 | /** 20 | * Whether the app is running using the development environment or not. 21 | * 22 | * @return YES if the app is using the development environment. 23 | */ 24 | + (BOOL)isDevelopment; 25 | 26 | /** 27 | * Whether the app is running using the staging environment or not. 28 | * 29 | * @return YES if the app is using the staging environment. 30 | */ 31 | + (BOOL)isStaging; 32 | 33 | /** 34 | * Whether the app is running using the production environment or not. 35 | * 36 | * @return YES if the app is using the production environment. 37 | */ 38 | + (BOOL)isProduction; 39 | 40 | /** 41 | * Whether the app is running tests. 42 | * 43 | * @return YES if the app is running tests. 44 | */ 45 | + (BOOL)isRunningTests; 46 | 47 | 48 | /** 49 | * Whether the app is running on a simulator or not. 50 | * 51 | * @return YES if the app is running on a simulator 52 | */ 53 | + (BOOL)isRunningOnTheSimulator; 54 | 55 | /** 56 | * A readable description of the current runtime environment. 57 | * 58 | * @return A string describing the runtime environment. For example, if the app is using the staging environment, this will return "Staging". If the app is using the development environment and it is also currently running tests, it will return "Development Tests". 59 | */ 60 | + (NSString *)environmentDescription; 61 | 62 | @end 63 | -------------------------------------------------------------------------------- /Rails/blog-app/public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The page you were looking for doesn't exist.

62 |

You may have mistyped the address or the page may have moved.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /Rails/blog-app/config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | resources :posts 3 | # The priority is based upon order of creation: first created -> highest priority. 4 | # See how all your routes lay out with "rake routes". 5 | 6 | # You can have the root of your site routed with "root" 7 | # root 'welcome#index' 8 | 9 | # Example of regular route: 10 | # get 'products/:id' => 'catalog#view' 11 | 12 | # Example of named route that can be invoked with purchase_url(id: product.id) 13 | # get 'products/:id/purchase' => 'catalog#purchase', as: :purchase 14 | 15 | # Example resource route (maps HTTP verbs to controller actions automatically): 16 | # resources :products 17 | 18 | # Example resource route with options: 19 | # resources :products do 20 | # member do 21 | # get 'short' 22 | # post 'toggle' 23 | # end 24 | # 25 | # collection do 26 | # get 'sold' 27 | # end 28 | # end 29 | 30 | # Example resource route with sub-resources: 31 | # resources :products do 32 | # resources :comments, :sales 33 | # resource :seller 34 | # end 35 | 36 | # Example resource route with more complex sub-resources: 37 | # resources :products do 38 | # resources :comments 39 | # resources :sales do 40 | # get 'recent', on: :collection 41 | # end 42 | # end 43 | 44 | # Example resource route with concerns: 45 | # concern :toggleable do 46 | # post 'toggle' 47 | # end 48 | # resources :posts, concerns: :toggleable 49 | # resources :photos, concerns: :toggleable 50 | 51 | # Example resource route within a namespace: 52 | # namespace :admin do 53 | # # Directs /admin/products/* to Admin::ProductsController 54 | # # (app/controllers/admin/products_controller.rb) 55 | # resources :products 56 | # end 57 | end 58 | -------------------------------------------------------------------------------- /Rails/blog-app/config/environments/test.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # The test environment is used exclusively to run your application's 5 | # test suite. You never need to work with it otherwise. Remember that 6 | # your test database is "scratch space" for the test suite and is wiped 7 | # and recreated between test runs. Don't rely on the data there! 8 | config.cache_classes = true 9 | 10 | # Do not eager load code on boot. This avoids loading your whole application 11 | # just for the purpose of running a single test. If you are using a tool that 12 | # preloads Rails for running tests, you may have to set it to true. 13 | config.eager_load = false 14 | 15 | # Configure static file server for tests with Cache-Control for performance. 16 | config.serve_static_files = true 17 | config.static_cache_control = 'public, max-age=3600' 18 | 19 | # Show full error reports and disable caching. 20 | config.consider_all_requests_local = true 21 | config.action_controller.perform_caching = false 22 | 23 | # Raise exceptions instead of rendering exception templates. 24 | config.action_dispatch.show_exceptions = false 25 | 26 | # Disable request forgery protection in test environment. 27 | config.action_controller.allow_forgery_protection = false 28 | 29 | # Tell Action Mailer not to deliver emails to the real world. 30 | # The :test delivery method accumulates sent emails in the 31 | # ActionMailer::Base.deliveries array. 32 | config.action_mailer.delivery_method = :test 33 | 34 | # Randomize the order test cases are executed. 35 | config.active_support.test_order = :random 36 | 37 | # Print deprecation notices to the stderr. 38 | config.active_support.deprecation = :stderr 39 | 40 | # Raises error for missing translations 41 | # config.action_view.raise_on_missing_translations = true 42 | end 43 | -------------------------------------------------------------------------------- /iOS/DesignPatternsSample/DesignPatternsSample/ModelParser.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ModelParser.swift 3 | // DesignPatternsSample 4 | // 5 | // Created by lgauthier on 9/27/15. 6 | // Copyright © 2015 Metova. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class ModelParser { 12 | 13 | // MARK: Restaurant 14 | 15 | class func parseRestaurantResponse(json: [String: AnyObject]) -> [Restaurant] { 16 | 17 | if let restaurantJSONArray = json[Constants.Web.Keys.Businesses] as? [[String: AnyObject]] { 18 | return ModelParser.parseRestaurants(restaurantJSONArray) 19 | } 20 | else { 21 | return [Restaurant]() 22 | } 23 | } 24 | 25 | 26 | 27 | class func parseRestaurants(jsonArray: [[String: AnyObject]]) -> [Restaurant] { 28 | 29 | var restaurants = [Restaurant]() 30 | 31 | for json in jsonArray { 32 | 33 | if let name = json[Constants.Web.Keys.Restaurant.Name] as? String { 34 | 35 | var location: Location? 36 | 37 | if let locationJSON = json[Constants.Web.Keys.Restaurant.Location] as? [String: AnyObject] { 38 | location = ModelParser.parseLocation(locationJSON) 39 | } 40 | 41 | let restaurant = Restaurant(name: name, location: location) 42 | 43 | restaurants.append(restaurant) 44 | } 45 | } 46 | 47 | return restaurants 48 | } 49 | 50 | 51 | 52 | // MARK: Location 53 | 54 | class func parseLocation(json: [String: AnyObject]) -> Location? { 55 | 56 | if let addressLines = json[Constants.Web.Keys.Location.DisplayAddress] as? [String] { 57 | 58 | let displayAddress = addressLines.joinWithSeparator("\n") 59 | return Location(displayAddress: displayAddress) 60 | } 61 | 62 | return nil 63 | } 64 | } -------------------------------------------------------------------------------- /iOS/DesignPatternsSample/Tests/LoginViewControllerTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LoginViewControllerTests.swift 3 | // DesignPatternsSample 4 | // 5 | // Created by lgauthier on 1/7/15. 6 | // Copyright (c) 2015 Metova. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import XCTest 11 | 12 | @testable import DesignPatternsSample 13 | 14 | class LoginViewControllerTests: XCTestCase { 15 | 16 | // MARK: Properties 17 | 18 | var testVC: LoginViewController! 19 | 20 | 21 | // MARK: Setup/Teardown 22 | 23 | override func setUp() { 24 | super.setUp() 25 | 26 | let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle()) 27 | testVC = storyboard.instantiateViewControllerWithIdentifier("LoginViewController") as! LoginViewController 28 | 29 | testVC.loadView() 30 | testVC.viewDidLoad() 31 | } 32 | 33 | override func tearDown() { 34 | 35 | super.tearDown() 36 | } 37 | 38 | 39 | // MARK: Tests 40 | 41 | func testUI() { 42 | 43 | XCTAssertNotNil(testVC.emailTextField, "LoginVC's email text field should not be nil") 44 | XCTAssertNotNil(testVC.passwordTextField, "LoginVC's password text field should not be nil") 45 | 46 | XCTAssertEqual(testVC.emailTextField.placeholder!, "Email", "LoginVC's email text field has incorrect placeholder text") 47 | XCTAssertEqual(testVC.passwordTextField.placeholder!, "Password", "LoginVC's password text field has incorrect placeholder text") 48 | } 49 | 50 | func testForValidPassword() { 51 | 52 | testVC.passwordTextField.text = "1234567" 53 | XCTAssertFalse(testVC.isPasswordFieldValid(), "The password text field must have at least 8 characters to be valid") 54 | 55 | testVC.passwordTextField.text = "12345678" 56 | XCTAssertTrue(testVC.isPasswordFieldValid(), "The password text field should be valid because it has 8 characters") 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Rails/blog-app/app/controllers/posts_controller.rb: -------------------------------------------------------------------------------- 1 | class PostsController < ApplicationController 2 | before_action :set_post, only: [:show, :edit, :update, :destroy] 3 | 4 | # GET /posts 5 | # GET /posts.json 6 | def index 7 | @posts = Post.all 8 | end 9 | 10 | # GET /posts/1 11 | # GET /posts/1.json 12 | def show 13 | end 14 | 15 | # GET /posts/new 16 | def new 17 | @post = Post.new 18 | end 19 | 20 | # GET /posts/1/edit 21 | def edit 22 | end 23 | 24 | # POST /posts 25 | # POST /posts.json 26 | def create 27 | @post = Post.new(post_params) 28 | 29 | respond_to do |format| 30 | if @post.save 31 | format.html { redirect_to @post, notice: 'Post was successfully created.' } 32 | format.json { render :show, status: :created, location: @post } 33 | else 34 | format.html { render :new } 35 | format.json { render json: @post.errors, status: :unprocessable_entity } 36 | end 37 | end 38 | end 39 | 40 | # PATCH/PUT /posts/1 41 | # PATCH/PUT /posts/1.json 42 | def update 43 | respond_to do |format| 44 | if @post.update(post_params) 45 | format.html { redirect_to @post, notice: 'Post was successfully updated.' } 46 | format.json { render :show, status: :ok, location: @post } 47 | else 48 | format.html { render :edit } 49 | format.json { render json: @post.errors, status: :unprocessable_entity } 50 | end 51 | end 52 | end 53 | 54 | # DELETE /posts/1 55 | # DELETE /posts/1.json 56 | def destroy 57 | @post.destroy 58 | respond_to do |format| 59 | format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' } 60 | format.json { head :no_content } 61 | end 62 | end 63 | 64 | private 65 | # Use callbacks to share common setup or constraints between actions. 66 | def set_post 67 | @post = Post.find(params[:id]) 68 | end 69 | 70 | # Never trust parameters from the scary internet, only allow the white list through. 71 | def post_params 72 | params.require(:post).permit(:title, :body) 73 | end 74 | end 75 | -------------------------------------------------------------------------------- /Android/Sample-Android/designpatterns/src/main/java/com/metova/designpatterns/ui/ViewHolder.java: -------------------------------------------------------------------------------- 1 | package com.metova.designpatterns.ui; 2 | 3 | import com.metova.designpatterns.R; 4 | 5 | import android.view.View; 6 | import android.widget.ImageView; 7 | import android.widget.TextView; 8 | 9 | /** 10 | * FLYWEIGHT PATTERN 11 | *

12 | * PROBLEM: findViewById() is an expensive method because it traverses through the view hierarchy 13 | * to find a view with a matching id. If called frequently it can affect ListView performance. 14 | *

15 | * INTENT: Create a ViewHolder class to act as a Flyweight object. Only create one instance 16 | * and then cache it for future use so any unneeded findViewById() calls will not be invoked. 17 | *

18 | * INFO: The ListView will make calls to the ListAdapter's getView() method each time it needs a view 19 | * at a given index. Because the ListView only holds a certain amount of views in memory at a time 20 | * it can end up recreating the same views over and over as needed, resulting in a lot of calls to 21 | * findViewById() for each new view it creates. To avoid this performance hit we can cache each 22 | * view returned from findViewById() into a ViewHolder object that can be reused the next time 23 | * the ListView recreates the same view. 24 | * 25 | */ 26 | public class ViewHolder { 27 | 28 | public final ImageView image; 29 | public final TextView name; 30 | public final TextView location; 31 | public final ImageView stars; 32 | public final ImageView type; 33 | 34 | public ViewHolder(View view) { 35 | image = (ImageView) view.findViewById(R.id.image); 36 | name = (TextView) view.findViewById(R.id.name); 37 | location = (TextView) view.findViewById(R.id.location); 38 | stars = (ImageView) view.findViewById(R.id.stars); 39 | type = (ImageView) view.findViewById(R.id.type); 40 | 41 | /* FLYWEIGHT PATTERN */ 42 | // Cache the ViewHolder object into the tag of the view so that it can be retrieved with 43 | // a getTag() call for the next time it is needed. 44 | view.setTag(this); 45 | } 46 | 47 | } 48 | 49 | 50 | -------------------------------------------------------------------------------- /iOS/DesignPatternsSample/DesignPatternsSample/BuildEnvironment.m: -------------------------------------------------------------------------------- 1 | // 2 | // BuildEnvironment.m 3 | // DesignPatternsSample 4 | // 5 | // Created by Metova on ___DATE___. 6 | // Copyright (c) 2015 Metova. All rights reserved. 7 | // 8 | 9 | #import "BuildEnvironment.h" 10 | 11 | #if BUILD_ENVIRONMENT == BUILD_ENVIRONMENT_DEVELOPMENT 12 | NSString *const kBaseURL = @"<#http://www.development.test.com#>"; 13 | 14 | #elif BUILD_ENVIRONMENT == BUILD_ENVIRONMENT_STAGING 15 | NSString *const kBaseURL = @"<#http://www.staging.test.com#>"; 16 | 17 | #elif BUILD_ENVIRONMENT == BUILD_ENVIRONMENT_PRODUCTION 18 | NSString *const kBaseURL = @"<#http://www.production.test.com#>"; 19 | 20 | #endif 21 | 22 | @implementation BuildEnvironment 23 | 24 | + (BOOL)isDevelopment 25 | { 26 | return BUILD_ENVIRONMENT == BUILD_ENVIRONMENT_DEVELOPMENT; 27 | } 28 | 29 | 30 | + (BOOL)isStaging 31 | { 32 | return BUILD_ENVIRONMENT == BUILD_ENVIRONMENT_STAGING; 33 | } 34 | 35 | 36 | + (BOOL)isProduction 37 | { 38 | return BUILD_ENVIRONMENT == BUILD_ENVIRONMENT_PRODUCTION; 39 | } 40 | 41 | 42 | + (BOOL)isRunningTests 43 | { 44 | NSString *injectBundle = [[NSProcessInfo processInfo] environment][@"XCInjectBundle"]; 45 | 46 | if (injectBundle != nil) 47 | { 48 | if ([[injectBundle lastPathComponent] isEqualToString:@"Tests.xctest"]) 49 | { 50 | return YES; 51 | } 52 | } 53 | 54 | return NO; 55 | } 56 | 57 | 58 | + (BOOL)isRunningOnTheSimulator 59 | { 60 | #if TARGET_IPHONE_SIMULATOR 61 | return YES; 62 | #else 63 | return NO; 64 | #endif 65 | } 66 | 67 | 68 | + (NSString *)environmentDescription 69 | { 70 | NSString *description = @"Unknown"; 71 | 72 | if ([BuildEnvironment isDevelopment]) 73 | { 74 | description = @"Development"; 75 | } 76 | else if ([BuildEnvironment isStaging]) 77 | { 78 | description = @"Staging"; 79 | } 80 | else if ([BuildEnvironment isProduction]) 81 | { 82 | description = @"Production"; 83 | } 84 | 85 | if (BuildEnvironment.isRunningTests) 86 | { 87 | description = [description stringByAppendingString:@"Tests"]; 88 | } 89 | 90 | return description; 91 | } 92 | 93 | @end 94 | -------------------------------------------------------------------------------- /iOS/DesignPatternsSample/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - AFNetworking (2.6.0): 3 | - AFNetworking/NSURLConnection (= 2.6.0) 4 | - AFNetworking/NSURLSession (= 2.6.0) 5 | - AFNetworking/Reachability (= 2.6.0) 6 | - AFNetworking/Security (= 2.6.0) 7 | - AFNetworking/Serialization (= 2.6.0) 8 | - AFNetworking/UIKit (= 2.6.0) 9 | - AFNetworking/NSURLConnection (2.6.0): 10 | - AFNetworking/Reachability 11 | - AFNetworking/Security 12 | - AFNetworking/Serialization 13 | - AFNetworking/NSURLSession (2.6.0): 14 | - AFNetworking/Reachability 15 | - AFNetworking/Security 16 | - AFNetworking/Serialization 17 | - AFNetworking/Reachability (2.6.0) 18 | - AFNetworking/Security (2.6.0) 19 | - AFNetworking/Serialization (2.6.0) 20 | - AFNetworking/UIKit (2.6.0): 21 | - AFNetworking/NSURLConnection 22 | - AFNetworking/NSURLSession 23 | - CocoaLumberjack (2.0.1): 24 | - CocoaLumberjack/Default (= 2.0.1) 25 | - CocoaLumberjack/Extensions (= 2.0.1) 26 | - CocoaLumberjack/Core (2.0.1) 27 | - CocoaLumberjack/Default (2.0.1): 28 | - CocoaLumberjack/Core 29 | - CocoaLumberjack/Extensions (2.0.1): 30 | - CocoaLumberjack/Default 31 | - Flannel (2.0.0): 32 | - CocoaLumberjack (~> 2.0.0-rc) 33 | - NYXImagesKit (2.3) 34 | - OCMock (3.1.5) 35 | - Reachability (3.2) 36 | - SDWebImage (3.7.3): 37 | - SDWebImage/Core (= 3.7.3) 38 | - SDWebImage/Core (3.7.3) 39 | - SVProgressHUD (1.1.3) 40 | - ThunderCats (1.0.13): 41 | - NYXImagesKit (~> 2.3) 42 | - SDWebImage (~> 3.7.1) 43 | 44 | DEPENDENCIES: 45 | - AFNetworking 46 | - CocoaLumberjack 47 | - Flannel 48 | - OCMock 49 | - Reachability 50 | - SVProgressHUD 51 | - ThunderCats (from `https://github.com/metova/ThunderCats.git`) 52 | 53 | EXTERNAL SOURCES: 54 | ThunderCats: 55 | :git: https://github.com/metova/ThunderCats.git 56 | 57 | CHECKOUT OPTIONS: 58 | ThunderCats: 59 | :commit: 0d651e341b64945c61c0202001f5ae1d079caa8e 60 | :git: https://github.com/metova/ThunderCats.git 61 | 62 | SPEC CHECKSUMS: 63 | AFNetworking: 79f7eb1a0fcfa7beb409332b2ca49afe9ce53b05 64 | CocoaLumberjack: 019d1361244274a6138c788c6cb80baabc13fb8f 65 | Flannel: fbc78ce2665073c9091aa05955d568df52b3c523 66 | NYXImagesKit: 8163e3335a40eaa173ca5bbbf81fafb57d3947eb 67 | OCMock: 4c2925291f80407c3738dd1db14d21d0cc278864 68 | Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96 69 | SDWebImage: 1d2b1a1efda1ade1b00b6f8498865f8ddedc8a84 70 | SVProgressHUD: 748080e4f36e603f6c02aec292664239df5279c1 71 | ThunderCats: da255740c7ae2db0c0daa88212ef74a5b22afd85 72 | 73 | COCOAPODS: 0.38.2 74 | -------------------------------------------------------------------------------- /iOS/DesignPatternsSample/DesignPatternsSample/WebService.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WebService.swift 3 | // DesignPatternsSample 4 | // 5 | // Created by Metova on ___DATE___. 6 | // Copyright (c) 2015 Metova. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // Pattern Example: Singleton 12 | /* 13 | 14 | Check list from https://sourcemaking.com/design_patterns/singleton 15 | 16 | 1. Define a private static attribute in the "single instance" class. 17 | 2. Define a public static accessor function in the class. 18 | 19 | These two steps are achieved in Swift using a single static `let` constant for "sharedInstance". It has the default access level of "internal" which makes it available to any class in the module. If we were writing a framework, we would want to declare sharedInstance as public as well as the ModelParser class itself. 20 | 21 | 22 | 3. Do "lazy initialization" (creation on first use) in the accessor function. 23 | 24 | Swift lazily initializes class constants (and variables) in a dispatch_once block. The dispatch_once block also makes it thread safe which, along with the use of the `let` keyword, ensures that one and only one instance of the class will exist. 25 | 26 | 27 | 4. Define all constructors to be protected or private. 28 | 29 | The default init constructor is declared as private. 30 | 31 | 32 | 5. Clients may only use the accessor function to manipulate the Singleton. 33 | 34 | sharedInstance is declared as a let constant. It's value can never be changed. 35 | 36 | */ 37 | 38 | class WebService { 39 | 40 | // MARK: Singleton 41 | 42 | static let sharedInstance = WebService() 43 | 44 | private init() {} 45 | 46 | 47 | 48 | // MARK: Properties 49 | 50 | private let sessionManager = AFHTTPSessionManager(baseURL: NSURL(string: kBaseURL)) 51 | 52 | 53 | 54 | // MARK: Methods 55 | 56 | func retrieveRestaurants(completion: (json: [String: AnyObject]) -> ()) { 57 | 58 | // We're just mocking a network request for this example: 59 | let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(2.0 * Double(NSEC_PER_SEC))) 60 | dispatch_after(delayTime, dispatch_get_main_queue(), { 61 | 62 | if let filePath = NSBundle.mainBundle().pathForResource("hot_chicken", ofType: "json"), 63 | let data = NSData(contentsOfFile: filePath) { 64 | 65 | let json = try! NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments) 66 | completion(json: (json as! [String: AnyObject])) 67 | } 68 | }) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /iOS/DesignPatternsSample/DesignPatternsSample/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /Android/Sample-Android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /Android/Sample-Android/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | 47 | 48 | 49 | 50 | 1.8 51 | 52 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /Android/Sample-Android/designpatterns/src/main/java/com/metova/designpatterns/data/HotChicken.java: -------------------------------------------------------------------------------- 1 | package com.metova.designpatterns.data; 2 | 3 | public class HotChicken implements Restaurant { 4 | 5 | long generated_id = 0; 6 | String id = null; 7 | String name = null; 8 | String phone = null; 9 | String url = null; 10 | String imageUrl = null; 11 | String ratingUrl = null; 12 | double rating = 0; 13 | int reviewCount = 0; 14 | String address = null; 15 | String city = null; 16 | String state = null; 17 | String zipCode = null; 18 | 19 | public long getGenerated_id() { 20 | return generated_id; 21 | } 22 | 23 | public void setGenerated_id(long generated_id) { 24 | this.generated_id = generated_id; 25 | } 26 | 27 | public String getId() { 28 | return id; 29 | } 30 | 31 | public void setId(String id) { 32 | this.id = id; 33 | } 34 | 35 | public String getName() { 36 | return name; 37 | } 38 | 39 | public void setName(String name) { 40 | this.name = name; 41 | } 42 | 43 | public String getPhone() { 44 | return phone; 45 | } 46 | 47 | public void setPhone(String phone) { 48 | this.phone = phone; 49 | } 50 | 51 | public String getUrl() { 52 | return url; 53 | } 54 | 55 | public void setUrl(String url) { 56 | this.url = url; 57 | } 58 | 59 | public String getImageUrl() { 60 | return imageUrl; 61 | } 62 | 63 | public void setImageUrl(String imageUrl) { 64 | this.imageUrl = imageUrl; 65 | } 66 | 67 | public String getRatingUrl() { 68 | return ratingUrl; 69 | } 70 | 71 | public void setRatingUrl(String ratingUrl) { 72 | this.ratingUrl = ratingUrl; 73 | } 74 | 75 | public double getRating() { 76 | return rating; 77 | } 78 | 79 | public void setRating(double rating) { 80 | this.rating = rating; 81 | } 82 | 83 | public int getReviewCount() { 84 | return reviewCount; 85 | } 86 | 87 | public void setReviewCount(int reviewCount) { 88 | this.reviewCount = reviewCount; 89 | } 90 | 91 | public String getAddress() { 92 | return address; 93 | } 94 | 95 | public void setAddress(String address) { 96 | this.address = address; 97 | } 98 | 99 | public String getCity() { 100 | return city; 101 | } 102 | 103 | public void setCity(String city) { 104 | this.city = city; 105 | } 106 | 107 | public String getState() { 108 | return state; 109 | } 110 | 111 | public void setState(String state) { 112 | this.state = state; 113 | } 114 | 115 | public String getZipCode() { 116 | return zipCode; 117 | } 118 | 119 | public void setZipCode(String zipCode) { 120 | this.zipCode = zipCode; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /iOS/DesignPatternsSample/DesignPatternsSample/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // DesignPatternsSample 4 | // 5 | // Created by Metova on ___DATE___. 6 | // Copyright (c) 2015 Metova. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | 12 | @UIApplicationMain 13 | class MetovaAppDelegate: UIResponder, UIApplicationDelegate { 14 | 15 | var window: UIWindow? 16 | let fileLogger = DDFileLogger() 17 | 18 | func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { 19 | 20 | setUpCocoaLumberjackLogger() 21 | 22 | DDLogSwift.info("Build Environment: " + BuildEnvironment.environmentDescription()) 23 | 24 | return true 25 | } 26 | 27 | 28 | func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) { 29 | 30 | DDLogSwift.error("\(error)") 31 | } 32 | 33 | 34 | func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) { 35 | 36 | DDLogSwift.info("Successfully registered for push notifications") 37 | } 38 | 39 | 40 | func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) { 41 | 42 | } 43 | 44 | 45 | // MARK: Helper Methods 46 | 47 | /** 48 | Adds four CocoaLumberjack loggers to the project: 49 | 50 | DDASLLogger - The Apple system logger. 51 | DDTTYLogger - The Xcode console logger. 52 | CrashlyticsLogger - Sends all CocoaLumberjack logs to the Crashlytics logging utility so console logs are sent with crash reports. (See http://support.crashlytics.com/knowledgebase/articles/92519-how-do-i-use-logging) 53 | DDFileLogger - Writes log statements to a file. This can be useful to provide a way for clients to send console logs when a bug occurs which doesn't cause a crash. 54 | */ 55 | func setUpCocoaLumberjackLogger() -> Void { 56 | 57 | let aslLogger = DDASLLogger.sharedInstance() 58 | let ttyLogger = DDTTYLogger.sharedInstance() 59 | 60 | aslLogger.logFormatter = FLAVerboseLogFormatter() 61 | ttyLogger.logFormatter = FLAVerboseLogFormatter() 62 | fileLogger.logFormatter = FLAVerboseLogFormatter() 63 | 64 | ttyLogger.colorsEnabled = true 65 | ttyLogger.setForegroundColor(UIColor(red: 0, green: 1.0, blue: 0.5, alpha: 1.0), backgroundColor: nil, forFlag: DDLogFlag.Debug) 66 | ttyLogger.setForegroundColor(UIColor(red: 0.44, green: 0.56, blue: 0.6, alpha: 1.0), backgroundColor: nil, forFlag: DDLogFlag.Verbose) 67 | 68 | fileLogger.rollingFrequency = (60 * 60 * 60) // 60 Hour Rolling Period 69 | fileLogger.logFileManager.maximumNumberOfLogFiles = 1 70 | 71 | DDLog.addLogger(aslLogger) 72 | DDLog.addLogger(ttyLogger) 73 | DDLog.addLogger(fileLogger) 74 | } 75 | } 76 | 77 | -------------------------------------------------------------------------------- /iOS/DesignPatternsSample/DesignPatternsSample/DDLogSwift.m: -------------------------------------------------------------------------------- 1 | // 2 | // DDLogSwift.m 3 | // DesignPatternsSample 4 | // 5 | // Created by Metova on ___DATE___. 6 | // Copyright (c) 2015 Metova. All rights reserved. 7 | // 8 | 9 | #import "DDLogSwift.h" 10 | #import "BuildEnvironment.h" 11 | 12 | #import 13 | #import 14 | #import 15 | #import 16 | #import 17 | 18 | #if BUILD_ENVIRONMENT == BUILD_ENVIRONMENT_DEVELOPMENT 19 | static const int ddLogLevel = LOG_LEVEL_VERBOSE; 20 | #elif BUILD_ENVIRONMENT == BUILD_ENVIRONMENT_STAGING 21 | static const int ddLogLevel = LOG_LEVEL_VERBOSE; 22 | #elif BUILD_ENVIRONMENT == BUILD_ENVIRONMENT_PRODUCTION 23 | static const int ddLogLevel = LOG_LEVEL_ERROR; 24 | #endif 25 | 26 | @implementation DDLogSwift 27 | 28 | + (void)error:(NSString *)message 29 | { 30 | DDLogError(message); 31 | } 32 | 33 | 34 | + (void)warn:(NSString *)message 35 | { 36 | DDLogWarn(message); 37 | } 38 | 39 | 40 | + (void)info:(NSString *)message 41 | { 42 | DDLogInfo(message); 43 | } 44 | 45 | 46 | + (void)debug:(NSString *)message 47 | { 48 | DDLogDebug(message); 49 | } 50 | 51 | 52 | + (void)verbose:(NSString *)message 53 | { 54 | DDLogVerbose(message); 55 | } 56 | 57 | 58 | + (void)logRequestInfo:(AFHTTPRequestOperation *)operation 59 | { 60 | if (operation != nil) 61 | { 62 | DDLogInfo(@"OPERATION: %@", operation); 63 | DDLogInfo(@"URL: %@", operation.request.URL.absoluteString); 64 | DDLogInfo(@"HEADERS: %@", operation.request.allHTTPHeaderFields); 65 | DDLogInfo(@"BODY: %@", [[NSString alloc] initWithData:operation.request.HTTPBody encoding:NSUTF8StringEncoding]); 66 | } 67 | else 68 | { 69 | DDLogError(@"Attempted to log a nil AFHTTPRequestOperation"); 70 | } 71 | } 72 | 73 | 74 | + (void)logSessionTaskInfo:(NSURLSessionDataTask *)task error:(NSError *)error 75 | { 76 | if (task != nil) 77 | { 78 | NSData *data = [NSJSONSerialization dataWithJSONObject:task.originalRequest.allHTTPHeaderFields 79 | options:NSJSONWritingPrettyPrinted 80 | error:nil]; 81 | 82 | NSString *headersDisplayedInJSONFormat = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 83 | 84 | NSString *logString = [NSString stringWithFormat:@"\n=============================LOG=START================================\nURL: %@\nMETHOD: %@\nHEADERS: %@\nBODY: %@\nERROR: %@\n================================LOG=END===============================", task.originalRequest.URL.absoluteString, task.originalRequest.HTTPMethod, headersDisplayedInJSONFormat, [[NSString alloc] initWithData:task.originalRequest.HTTPBody encoding:NSUTF8StringEncoding], error.localizedDescription]; 85 | 86 | if (error) { 87 | DDLogError(logString); 88 | } 89 | else { 90 | DDLogVerbose(logString); 91 | } 92 | } 93 | else 94 | { 95 | DDLogError(@"Attempted to log a nil NSURLSessionDataTask"); 96 | } 97 | } 98 | 99 | @end 100 | -------------------------------------------------------------------------------- /Android/Sample-Android/designpatterns/src/main/java/com/metova/designpatterns/data/Burger.java: -------------------------------------------------------------------------------- 1 | package com.metova.designpatterns.data; 2 | 3 | public class Burger implements Restaurant{ 4 | 5 | long generated_id = 0; 6 | String id = null; 7 | String name = null; 8 | String phone = null; 9 | String url = null; 10 | String imageUrl = null; 11 | String ratingUrl = null; 12 | double rating = 0; 13 | int reviewCount = 0; 14 | String address = null; 15 | String city = null; 16 | String state = null; 17 | String zipCode = null; 18 | 19 | @Override 20 | public long getGenerated_id() { 21 | return generated_id; 22 | } 23 | 24 | @Override 25 | public void setGenerated_id(long generated_id) { 26 | this.generated_id = generated_id; 27 | } 28 | 29 | @Override 30 | public String getId() { 31 | return id; 32 | } 33 | 34 | @Override 35 | public void setId(String id) { 36 | this.id = id; 37 | } 38 | 39 | @Override 40 | public String getName() { 41 | return name; 42 | } 43 | 44 | @Override 45 | public void setName(String name) { 46 | this.name = name; 47 | } 48 | 49 | @Override 50 | public String getPhone() { 51 | return phone; 52 | } 53 | 54 | @Override 55 | public void setPhone(String phone) { 56 | this.phone = phone; 57 | } 58 | 59 | @Override 60 | public String getUrl() { 61 | return url; 62 | } 63 | 64 | @Override 65 | public void setUrl(String url) { 66 | this.url = url; 67 | } 68 | 69 | @Override 70 | public String getImageUrl() { 71 | return imageUrl; 72 | } 73 | 74 | @Override 75 | public void setImageUrl(String imageUrl) { 76 | this.imageUrl = imageUrl; 77 | } 78 | 79 | @Override 80 | public String getRatingUrl() { 81 | return ratingUrl; 82 | } 83 | 84 | @Override 85 | public void setRatingUrl(String ratingUrl) { 86 | this.ratingUrl = ratingUrl; 87 | } 88 | 89 | @Override 90 | public double getRating() { 91 | return rating; 92 | } 93 | 94 | @Override 95 | public void setRating(double rating) { 96 | this.rating = rating; 97 | } 98 | 99 | @Override 100 | public int getReviewCount() { 101 | return reviewCount; 102 | } 103 | 104 | @Override 105 | public void setReviewCount(int reviewCount) { 106 | this.reviewCount = reviewCount; 107 | } 108 | 109 | @Override 110 | public String getAddress() { 111 | return address; 112 | } 113 | 114 | @Override 115 | public void setAddress(String address) { 116 | this.address = address; 117 | } 118 | 119 | @Override 120 | public String getCity() { 121 | return city; 122 | } 123 | 124 | @Override 125 | public void setCity(String city) { 126 | this.city = city; 127 | } 128 | 129 | @Override 130 | public String getState() { 131 | return state; 132 | } 133 | 134 | @Override 135 | public void setState(String state) { 136 | this.state = state; 137 | } 138 | 139 | @Override 140 | public String getZipCode() { 141 | return zipCode; 142 | } 143 | 144 | @Override 145 | public void setZipCode(String zipCode) { 146 | this.zipCode = zipCode; 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /Rails/blog-app/config/environments/production.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # Code is not reloaded between requests. 5 | config.cache_classes = true 6 | 7 | # Eager load code on boot. This eager loads most of Rails and 8 | # your application in memory, allowing both threaded web servers 9 | # and those relying on copy on write to perform better. 10 | # Rake tasks automatically ignore this option for performance. 11 | config.eager_load = true 12 | 13 | # Full error reports are disabled and caching is turned on. 14 | config.consider_all_requests_local = false 15 | config.action_controller.perform_caching = true 16 | 17 | # Enable Rack::Cache to put a simple HTTP cache in front of your application 18 | # Add `rack-cache` to your Gemfile before enabling this. 19 | # For large-scale production use, consider using a caching reverse proxy like 20 | # NGINX, varnish or squid. 21 | # config.action_dispatch.rack_cache = true 22 | 23 | # Disable serving static files from the `/public` folder by default since 24 | # Apache or NGINX already handles this. 25 | config.serve_static_files = ENV['RAILS_SERVE_STATIC_FILES'].present? 26 | 27 | # Compress JavaScripts and CSS. 28 | config.assets.js_compressor = :uglifier 29 | # config.assets.css_compressor = :sass 30 | 31 | # Do not fallback to assets pipeline if a precompiled asset is missed. 32 | config.assets.compile = false 33 | 34 | # Asset digests allow you to set far-future HTTP expiration dates on all assets, 35 | # yet still be able to expire them through the digest params. 36 | config.assets.digest = true 37 | 38 | # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb 39 | 40 | # Specifies the header that your server uses for sending files. 41 | # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache 42 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX 43 | 44 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 45 | # config.force_ssl = true 46 | 47 | # Use the lowest log level to ensure availability of diagnostic information 48 | # when problems arise. 49 | config.log_level = :debug 50 | 51 | # Prepend all log lines with the following tags. 52 | # config.log_tags = [ :subdomain, :uuid ] 53 | 54 | # Use a different logger for distributed setups. 55 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) 56 | 57 | # Use a different cache store in production. 58 | # config.cache_store = :mem_cache_store 59 | 60 | # Enable serving of images, stylesheets, and JavaScripts from an asset server. 61 | # config.action_controller.asset_host = 'http://assets.example.com' 62 | 63 | # Ignore bad email addresses and do not raise email delivery errors. 64 | # Set this to true and configure the email server for immediate delivery to raise delivery errors. 65 | # config.action_mailer.raise_delivery_errors = false 66 | 67 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 68 | # the I18n.default_locale when a translation cannot be found). 69 | config.i18n.fallbacks = true 70 | 71 | # Send deprecation notices to registered listeners. 72 | config.active_support.deprecation = :notify 73 | 74 | # Use default logging formatter so that PID and timestamp are not suppressed. 75 | config.log_formatter = ::Logger::Formatter.new 76 | 77 | # Do not dump schema after migrations. 78 | config.active_record.dump_schema_after_migration = false 79 | end 80 | -------------------------------------------------------------------------------- /Android/Sample-Android/designpatterns/src/main/java/com/metova/designpatterns/ui/ListAdapter.java: -------------------------------------------------------------------------------- 1 | package com.metova.designpatterns.ui; 2 | 3 | import com.koushikdutta.ion.Ion; 4 | import com.metova.designpatterns.R; 5 | import com.metova.designpatterns.data.Burger; 6 | import com.metova.designpatterns.data.Restaurant; 7 | 8 | import android.content.Context; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.widget.BaseAdapter; 13 | 14 | import java.util.ArrayList; 15 | 16 | 17 | /** 18 | * ADAPTER PATTERN 19 | *

20 | * PROBLEM: It is difficult to reuse different types of views and display them as a list. 21 | *

22 | * INTENT: Creating an intermediary abstraction that translates one component to another. The ListAdapter 23 | * allows different views to be displayed in a list even though they may have incompatible interfaces. 24 | * The ListView can display any data provided that is wrapped in a ListAdapter. 25 | *

26 | * INFO: The overridden methods allow the adapter to interact with the underlying data. By calling 27 | * getCount(), the ListAdapter knows how many items it needs to display. The getView() is then called 28 | * getCount() number of times. For each call to the getView() method, getItem() is called and the ViewHolder 29 | * is inflated in that particle view in the ListAdapter. The getId() is used to keep track of the items 30 | * and for the FlyWeight pattern. 31 | * 32 | */ 33 | 34 | public class ListAdapter extends BaseAdapter { 35 | 36 | private static final String TAG = ListAdapter.class.getSimpleName(); 37 | 38 | private ArrayList mRestaurantList; 39 | 40 | public ListAdapter(ArrayList restaurantList) { 41 | mRestaurantList = restaurantList; 42 | } 43 | 44 | @Override 45 | public int getCount() { 46 | return mRestaurantList.size(); 47 | } 48 | 49 | @Override 50 | public Restaurant getItem(int position) { 51 | return mRestaurantList.get(position); 52 | } 53 | 54 | @Override 55 | public long getItemId(int position) { 56 | return getItem(position).getGenerated_id(); 57 | } 58 | 59 | @Override 60 | public View getView(int position, View convertView, ViewGroup parent) { 61 | 62 | /* FLYWEIGHT PATTERN */ 63 | // Determine if we can need to create a new view or if the list view is recreated a view that 64 | // it has already received from a getView call. If convertView is null we know that we should 65 | // create a new view, otherwise we know that getView() has already created the view and we 66 | // can use our Flyweight ViewHolder object that is cached for us in the tag. 67 | Restaurant restaurant = getItem(position); 68 | Context context = parent.getContext(); 69 | ViewHolder holder; 70 | if (convertView == null) { 71 | convertView = LayoutInflater.from(context).inflate(R.layout.restaurant_item, parent); 72 | holder = new ViewHolder(convertView); 73 | } else { 74 | holder = (ViewHolder) convertView.getTag(); 75 | } 76 | 77 | if (restaurant instanceof Burger) { 78 | holder.type.setImageResource(R.drawable.burger); 79 | } else { 80 | holder.type.setImageResource(R.drawable.chicken); 81 | } 82 | 83 | Ion.with(context) 84 | .load(restaurant.getImageUrl()) 85 | .withBitmap() 86 | .placeholder(R.drawable.loading) 87 | .error(R.drawable.error) 88 | .intoImageView(holder.image); 89 | 90 | Ion.with(context) 91 | .load(restaurant.getRatingUrl()) 92 | .withBitmap() 93 | .centerInside() 94 | .intoImageView(holder.stars); 95 | 96 | holder.name.setText(restaurant.getName()); 97 | holder.location.setText(restaurant.getCity()); 98 | 99 | return convertView; 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /Rails/blog-app/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | actionmailer (4.2.4) 5 | actionpack (= 4.2.4) 6 | actionview (= 4.2.4) 7 | activejob (= 4.2.4) 8 | mail (~> 2.5, >= 2.5.4) 9 | rails-dom-testing (~> 1.0, >= 1.0.5) 10 | actionpack (4.2.4) 11 | actionview (= 4.2.4) 12 | activesupport (= 4.2.4) 13 | rack (~> 1.6) 14 | rack-test (~> 0.6.2) 15 | rails-dom-testing (~> 1.0, >= 1.0.5) 16 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 17 | actionview (4.2.4) 18 | activesupport (= 4.2.4) 19 | builder (~> 3.1) 20 | erubis (~> 2.7.0) 21 | rails-dom-testing (~> 1.0, >= 1.0.5) 22 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 23 | activejob (4.2.4) 24 | activesupport (= 4.2.4) 25 | globalid (>= 0.3.0) 26 | activemodel (4.2.4) 27 | activesupport (= 4.2.4) 28 | builder (~> 3.1) 29 | activerecord (4.2.4) 30 | activemodel (= 4.2.4) 31 | activesupport (= 4.2.4) 32 | arel (~> 6.0) 33 | activesupport (4.2.4) 34 | i18n (~> 0.7) 35 | json (~> 1.7, >= 1.7.7) 36 | minitest (~> 5.1) 37 | thread_safe (~> 0.3, >= 0.3.4) 38 | tzinfo (~> 1.1) 39 | arel (6.0.3) 40 | binding_of_caller (0.7.2) 41 | debug_inspector (>= 0.0.1) 42 | builder (3.2.2) 43 | byebug (6.0.2) 44 | coffee-rails (4.1.0) 45 | coffee-script (>= 2.2.0) 46 | railties (>= 4.0.0, < 5.0) 47 | coffee-script (2.4.1) 48 | coffee-script-source 49 | execjs 50 | coffee-script-source (1.9.1.1) 51 | debug_inspector (0.0.2) 52 | erubis (2.7.0) 53 | execjs (2.6.0) 54 | globalid (0.3.6) 55 | activesupport (>= 4.1.0) 56 | i18n (0.7.0) 57 | jbuilder (2.3.2) 58 | activesupport (>= 3.0.0, < 5) 59 | multi_json (~> 1.2) 60 | jquery-rails (4.0.5) 61 | rails-dom-testing (~> 1.0) 62 | railties (>= 4.2.0) 63 | thor (>= 0.14, < 2.0) 64 | json (1.8.3) 65 | loofah (2.0.3) 66 | nokogiri (>= 1.5.9) 67 | mail (2.6.3) 68 | mime-types (>= 1.16, < 3) 69 | mime-types (2.6.2) 70 | mini_portile (0.6.2) 71 | minitest (5.8.1) 72 | multi_json (1.11.2) 73 | nokogiri (1.6.6.2) 74 | mini_portile (~> 0.6.0) 75 | rack (1.6.4) 76 | rack-test (0.6.3) 77 | rack (>= 1.0) 78 | rails (4.2.4) 79 | actionmailer (= 4.2.4) 80 | actionpack (= 4.2.4) 81 | actionview (= 4.2.4) 82 | activejob (= 4.2.4) 83 | activemodel (= 4.2.4) 84 | activerecord (= 4.2.4) 85 | activesupport (= 4.2.4) 86 | bundler (>= 1.3.0, < 2.0) 87 | railties (= 4.2.4) 88 | sprockets-rails 89 | rails-deprecated_sanitizer (1.0.3) 90 | activesupport (>= 4.2.0.alpha) 91 | rails-dom-testing (1.0.7) 92 | activesupport (>= 4.2.0.beta, < 5.0) 93 | nokogiri (~> 1.6.0) 94 | rails-deprecated_sanitizer (>= 1.0.1) 95 | rails-html-sanitizer (1.0.2) 96 | loofah (~> 2.0) 97 | railties (4.2.4) 98 | actionpack (= 4.2.4) 99 | activesupport (= 4.2.4) 100 | rake (>= 0.8.7) 101 | thor (>= 0.18.1, < 2.0) 102 | rake (10.4.2) 103 | rdoc (4.2.0) 104 | sass (3.4.18) 105 | sass-rails (5.0.4) 106 | railties (>= 4.0.0, < 5.0) 107 | sass (~> 3.1) 108 | sprockets (>= 2.8, < 4.0) 109 | sprockets-rails (>= 2.0, < 4.0) 110 | tilt (>= 1.1, < 3) 111 | sdoc (0.4.1) 112 | json (~> 1.7, >= 1.7.7) 113 | rdoc (~> 4.0) 114 | spring (1.4.0) 115 | sprockets (3.3.5) 116 | rack (> 1, < 3) 117 | sprockets-rails (2.3.3) 118 | actionpack (>= 3.0) 119 | activesupport (>= 3.0) 120 | sprockets (>= 2.8, < 4.0) 121 | sqlite3 (1.3.10) 122 | thor (0.19.1) 123 | thread_safe (0.3.5) 124 | tilt (2.0.1) 125 | turbolinks (2.5.3) 126 | coffee-rails 127 | tzinfo (1.2.2) 128 | thread_safe (~> 0.1) 129 | uglifier (2.7.2) 130 | execjs (>= 0.3.0) 131 | json (>= 1.8.0) 132 | web-console (2.2.1) 133 | activemodel (>= 4.0) 134 | binding_of_caller (>= 0.7.2) 135 | railties (>= 4.0) 136 | sprockets-rails (>= 2.0, < 4.0) 137 | 138 | PLATFORMS 139 | ruby 140 | 141 | DEPENDENCIES 142 | byebug 143 | coffee-rails (~> 4.1.0) 144 | jbuilder (~> 2.0) 145 | jquery-rails 146 | rails (= 4.2.4) 147 | sass-rails (~> 5.0) 148 | sdoc (~> 0.4.0) 149 | spring 150 | sqlite3 151 | turbolinks 152 | uglifier (>= 1.3.0) 153 | web-console (~> 2.0) 154 | 155 | BUNDLED WITH 156 | 1.10.6 157 | -------------------------------------------------------------------------------- /iOS/DesignPatternsSample/DesignPatternsSample/RestaurantCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 24 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /iOS/DesignPatternsSample/DesignPatternsSample.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 74 | 75 | 81 | 82 | 83 | 84 | 85 | 86 | 92 | 93 | 99 | 100 | 101 | 102 | 104 | 105 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Overview # 2 | 3 | The goal of this repository is to demonstrate use cases for design patterns and help solidify your understanding with simple code examples. 4 | 5 | If you are a web or mobile developer you may not be aware that you use some of these patterns every day. This repository will demonstrate how to apply design patterns to the iOS, Android, and Rails frameworks and give you a deeper understanding of when and how to use these patterns. 6 | 7 | # Design Patterns # 8 | 9 | The following list is a compilation of design patterns that we have explanations and code examples for. 10 | 11 | 12 | ## Singleton ## 13 | Reference: [Singleton Pattern](https://sourcemaking.com/design_patterns/singleton) 14 | 15 | #### Intent #### 16 | >- Ensure a class has only one instance, and provide a global point of access to it. 17 | - Encapsulated "just-in-time initialization" or "initialization on first use". 18 | 19 | #### Problem #### 20 | >Application needs one, and only one, instance of an object. Additionally, lazy initialization and global access are necessary. 21 | 22 | #### Examples #### 23 | 24 | - [DataManager - Android](https://github.com/metova/design-patterns-sample/blob/master/Android/Sample-Android/designpatterns/src/main/java/com/metova/designpatterns/data/DataManager.java) 25 | - [WebService - iOS](https://github.com/metova/design-patterns-sample/blob/master/iOS/DesignPatternsSample/DesignPatternsSample/WebService.swift) 26 | 27 | ## Factory ## 28 | 29 | #### Intent #### 30 | >- Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses. 31 | - Defining a "virtual" constructor. 32 | - The new operator considered harmful. 33 | 34 | #### Problem #### 35 | >A framework needs to standardize the architectural model for a range of applications, but allow for individual applications to define their own domain objects and provide for their instantiation. 36 | 37 | #### Examples #### 38 | [RestaurantFactory](https://github.com/metova/design-patterns-sample/blob/feature/android/Android/Sample-Android/designpatterns/src/main/java/com/metova/designpatterns/data/RestaurantFactory.java) 39 | 40 | ## Adapter ## 41 | References: 42 | 43 | - [Adapter Pattern](https://sourcemaking.com/design_patterns/adapter) 44 | - [ListAdapter Docs](http://developer.android.com/reference/android/widget/ListAdapter.html) 45 | 46 | #### Intent #### 47 | >- Convert the interface of a class into another interface clients expect. 48 | - Adapter lets classes work together that couldn't otherwise because of incompatible interfaces. 49 | - Wrap an existing class with a new interface. 50 | Impedance match an old component to a new system 51 | 52 | #### Problem #### 53 | >An "off the shelf" component offers compelling functionality that you would like to reuse, but its "view of the world" is not compatible with the philosophy and architecture of the system currently being developed. 54 | 55 | #### Examples #### 56 | - [ListAdapter - Android](https://github.com/metova/design-patterns-sample/blob/master/Android/Sample-Android/designpatterns/src/main/java/com/metova/designpatterns/ui/ListAdapter.java) 57 | 58 | ## Flyweight ## 59 | References: 60 | 61 | - [Flyweight Pattern](https://sourcemaking.com/design_patterns/flyweight) 62 | - [ViewHolder Docs](http://developer.android.com/training/improving-layouts/smooth-scrolling.html#ViewHolder) 63 | 64 | #### Intent #### 65 | >- Use sharing to support large numbers of fine-grained objects efficiently. 66 | - The Motif GUI strategy of replacing heavy-weight widgets with light-weight gadgets. 67 | 68 | #### Problem #### 69 | >Designing objects down to the lowest levels of system "granularity" provides optimal flexibility, but can be unacceptably expensive in terms of performance and memory usage. 70 | 71 | #### Examples #### 72 | [ViewHolder - Android](https://github.com/metova/design-patterns-sample/blob/master/Android/Sample-Android/designpatterns/src/main/java/com/metova/designpatterns/ui/ViewHolder.java#L10) 73 | 74 | ## Observer ## 75 | 76 | #### Intent #### 77 | >- Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically. 78 | - Encapsulate the core (or common or engine) components in a Subject abstraction, and the variable (or optional or user interface) components in an Observer hierarchy. 79 | - The "View" part of Model-View-Controller. 80 | 81 | #### Problem #### 82 | >A large monolithic design does not scale well as new graphing or monitoring requirements are levied. 83 | 84 | #### Examples #### 85 | [NSNotificationCenter - iOS](https://github.com/metova/design-patterns-sample/blob/master/iOS/DesignPatternsSample/DesignPatternsSample/RestaurantListViewController.swift#L35) 86 | 87 | ## Delegation ## 88 | Reference: [Delegation Pattern](https://developer.apple.com/library/ios/documentation/General/Conceptual/DevPedia-CocoaCore/Delegation.html) 89 | 90 | #### Intent #### 91 | >- Allow an object to act on behalf of, or in coordination with, another object. 92 | - Clients can customize behavior of another object while remaining fairly decoupled. 93 | 94 | #### Problem #### 95 | > You want to customize the behavior of an object when inheritance is either not feasible, or inheritance doesn't allow an object to maintain a separation of concerns. 96 | 97 | #### Examples #### 98 | [UITableView - iOS](https://github.com/metova/design-patterns-sample/blob/master/iOS/DesignPatternsSample/DesignPatternsSample/RestaurantListViewController.swift#L71) 99 | -------------------------------------------------------------------------------- /iOS/DesignPatternsSample/DesignPatternsSample.xcodeproj/xcshareddata/xcschemes/DesignPatternsSample.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 45 | 46 | 48 | 54 | 55 | 56 | 58 | 64 | 65 | 66 | 67 | 68 | 74 | 75 | 76 | 77 | 78 | 79 | 89 | 91 | 97 | 98 | 99 | 100 | 104 | 105 | 106 | 107 | 108 | 109 | 115 | 117 | 123 | 124 | 125 | 126 | 128 | 129 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /Android/Sample-Android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /iOS/DesignPatternsSample/DesignPatternsSample/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /Android/Sample-Android/designpatterns/src/main/java/com/metova/designpatterns/data/DataManager.java: -------------------------------------------------------------------------------- 1 | package com.metova.designpatterns.data; 2 | 3 | import android.content.Context; 4 | import android.util.Log; 5 | 6 | import com.metova.designpatterns.R; 7 | 8 | import org.json.JSONArray; 9 | import org.json.JSONException; 10 | import org.json.JSONObject; 11 | 12 | import java.io.BufferedReader; 13 | import java.io.IOException; 14 | import java.io.InputStream; 15 | import java.io.InputStreamReader; 16 | import java.io.Reader; 17 | import java.io.StringWriter; 18 | import java.io.Writer; 19 | import java.util.ArrayList; 20 | import java.util.Collections; 21 | import java.util.Comparator; 22 | import java.util.Enumeration; 23 | 24 | /** 25 | * SINGLETON PATTERN 26 | *

27 | * PROBLEM: Application needs one, and only one, instance of an object. Additionally, lazy initialization and global access are necessary. 28 | *

29 | * INTENT: Ensure a class has only one instance, and provide a global point of access to it. 30 | * Encapsulated "just-in-time initialization" or "initialization on first use" 31 | *

32 | * INFO: The static getInstance() method provides any class with the same instance of this class. 33 | * The the first time getInstance() is called, a new DataManager object is instantiated. 34 | * Future calls to getInstance() will return the same instance of the DataManager object. 35 | * 36 | */ 37 | 38 | public class DataManager { 39 | 40 | private static final String TAG = DataManager.class.getSimpleName(); 41 | 42 | /** Check list item 1: define a private static attribute in the singleton class */ 43 | private static DataManager dataManager; 44 | 45 | private ArrayList restaurantList; 46 | 47 | /** Check list item 2: define a public static accessor function in the class */ 48 | public static DataManager getInstance() { 49 | 50 | /** Check list item 3: do "lazy instantiation" in the accessor function 51 | * Check list item 4: private/protected constructor */ 52 | if (dataManager == null) { 53 | dataManager = new DataManager(); 54 | } 55 | 56 | return dataManager; 57 | } 58 | 59 | public void initialize(Context context) { 60 | 61 | restaurantList = new ArrayList<>(); 62 | 63 | JSONObject object = openJsonData(context, R.raw.hot_chicken); 64 | parseJson(object, RestaurantFactory.RestaurantType.HOT_CHICKEN); 65 | object = openJsonData(context, R.raw.burger); 66 | parseJson(object, RestaurantFactory.RestaurantType.BURGER); 67 | 68 | } 69 | 70 | public ArrayList getRestaurantList() { 71 | return restaurantList; 72 | } 73 | 74 | private void parseJson(JSONObject parentObject, RestaurantFactory.RestaurantType type) { 75 | 76 | try { 77 | JSONArray businessArray = parentObject.getJSONArray("businesses"); 78 | 79 | JSONObject restaurantObject; 80 | Restaurant restaurant; 81 | for (int i = 0; i < businessArray.length(); i++) { 82 | restaurantObject = businessArray.getJSONObject(i); 83 | restaurant = parseRestaurant(restaurantObject, i, type); 84 | 85 | if (restaurant != null) { 86 | restaurantList.add(restaurant); 87 | Log.d(TAG, "Added new restaurant: " + restaurant.getName()); 88 | } 89 | } 90 | 91 | Collections.sort(restaurantList, new Comparator() { 92 | @Override 93 | public int compare(Restaurant lhs, Restaurant rhs) { 94 | return lhs.getName().compareTo(rhs.getName()); 95 | } 96 | }); 97 | 98 | } catch (JSONException e) { 99 | e.printStackTrace(); 100 | } 101 | } 102 | 103 | private Restaurant parseRestaurant(JSONObject restaurantObject, long id, RestaurantFactory.RestaurantType type) { 104 | 105 | Restaurant restaurant = RestaurantFactory.getRestaurant(type); 106 | 107 | if (restaurant != null) { 108 | try { 109 | restaurant.setGenerated_id(id); 110 | restaurant.setId(restaurantObject.getString("id")); 111 | restaurant.setName(restaurantObject.getString("name")); 112 | restaurant.setImageUrl(restaurantObject.getString("image_url")); 113 | restaurant.setPhone(restaurantObject.getString("phone")); 114 | restaurant.setUrl(restaurantObject.getString("url")); 115 | restaurant.setRating(restaurantObject.getDouble("rating")); 116 | restaurant.setRatingUrl(restaurantObject.getString("rating_img_url")); 117 | restaurant.setReviewCount(restaurantObject.getInt("review_count")); 118 | 119 | JSONObject locationObject = restaurantObject.getJSONObject("location"); 120 | restaurant.setCity(locationObject.getString("city")); 121 | restaurant.setAddress(locationObject.getString("address")); 122 | restaurant.setZipCode(locationObject.getString("postal_code")); 123 | restaurant.setState(locationObject.getString("state_code")); 124 | 125 | } catch (JSONException e) { 126 | Log.e(TAG, "Error parsing restaurant", e); 127 | return null; 128 | } 129 | } 130 | 131 | return restaurant; 132 | } 133 | 134 | private JSONObject openJsonData(Context context, int resourceId) { 135 | 136 | InputStream is = context.getResources().openRawResource(resourceId); 137 | Writer writer = new StringWriter(); 138 | char[] buffer = new char[1024]; 139 | 140 | try { 141 | Reader reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); 142 | int n; 143 | while ((n = reader.read(buffer)) != -1) { 144 | writer.write(buffer, 0, n); 145 | } 146 | } catch (IOException e) { 147 | Log.e(TAG, "Error opening JSON data", e); 148 | } finally { 149 | try { 150 | is.close(); 151 | } catch (IOException e) { 152 | e.printStackTrace(); 153 | } 154 | } 155 | 156 | String jsonString = writer.toString(); 157 | JSONObject jsonObject = null; 158 | try { 159 | jsonObject = new JSONObject(jsonString); 160 | } catch (JSONException e) { 161 | Log.e(TAG, "Error creating JSON object", e); 162 | } 163 | 164 | return jsonObject; 165 | } 166 | 167 | } 168 | -------------------------------------------------------------------------------- /Android/Sample-Android/designpatterns/designpatterns.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /iOS/DesignPatternsSample/Crashlytics.framework/Headers/Crashlytics.h: -------------------------------------------------------------------------------- 1 | // 2 | // Crashlytics.h 3 | // Crashlytics 4 | // 5 | // Copyright 2013 Crashlytics, Inc. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | /** 11 | * 12 | * The CLS_LOG macro provides as easy way to gather more information in your log messages that are 13 | * sent with your crash data. CLS_LOG prepends your custom log message with the function name and 14 | * line number where the macro was used. If your app was built with the DEBUG preprocessor macro 15 | * defined CLS_LOG uses the CLSNSLog function which forwards your log message to NSLog and CLSLog. 16 | * If the DEBUG preprocessor macro is not defined CLS_LOG uses CLSLog only. 17 | * 18 | * Example output: 19 | * -[AppDelegate login:] line 134 $ login start 20 | * 21 | * If you would like to change this macro, create a new header file, unset our define and then define 22 | * your own version. Make sure this new header file is imported after the Crashlytics header file. 23 | * 24 | * #undef CLS_LOG 25 | * #define CLS_LOG(__FORMAT__, ...) CLSNSLog... 26 | * 27 | **/ 28 | #ifdef DEBUG 29 | #define CLS_LOG(__FORMAT__, ...) CLSNSLog((@"%s line %d $ " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__) 30 | #else 31 | #define CLS_LOG(__FORMAT__, ...) CLSLog((@"%s line %d $ " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__) 32 | #endif 33 | 34 | /** 35 | * 36 | * Add logging that will be sent with your crash data. This logging will not show up in the system.log 37 | * and will only be visible in your Crashlytics dashboard. 38 | * 39 | **/ 40 | OBJC_EXTERN void CLSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2); 41 | OBJC_EXTERN void CLSLogv(NSString *format, va_list args) NS_FORMAT_FUNCTION(1,0); 42 | 43 | /** 44 | * 45 | * Add logging that will be sent with your crash data. This logging will show up in the system.log 46 | * and your Crashlytics dashboard. It is not recommended for Release builds. 47 | * 48 | **/ 49 | OBJC_EXTERN void CLSNSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2); 50 | OBJC_EXTERN void CLSNSLogv(NSString *format, va_list args) NS_FORMAT_FUNCTION(1,0); 51 | 52 | 53 | @protocol CrashlyticsDelegate; 54 | 55 | @interface Crashlytics : NSObject 56 | 57 | @property (nonatomic, readonly, copy) NSString *apiKey; 58 | @property (nonatomic, readonly, copy) NSString *version; 59 | @property (nonatomic, assign) BOOL debugMode; 60 | 61 | @property (nonatomic, assign) NSObject *delegate; 62 | 63 | /** 64 | * 65 | * The recommended way to install Crashlytics into your application is to place a call 66 | * to +startWithAPIKey: in your -application:didFinishLaunchingWithOptions: method. 67 | * 68 | * This delay defaults to 1 second in order to generally give the application time to 69 | * fully finish launching. 70 | * 71 | **/ 72 | + (Crashlytics *)startWithAPIKey:(NSString *)apiKey; 73 | + (Crashlytics *)startWithAPIKey:(NSString *)apiKey afterDelay:(NSTimeInterval)delay; 74 | 75 | /** 76 | * 77 | * If you need the functionality provided by the CrashlyticsDelegate protocol, you can use 78 | * these convenience methods to activate the framework and set the delegate in one call. 79 | * 80 | **/ 81 | + (Crashlytics *)startWithAPIKey:(NSString *)apiKey delegate:(NSObject *)delegate; 82 | + (Crashlytics *)startWithAPIKey:(NSString *)apiKey delegate:(NSObject *)delegate afterDelay:(NSTimeInterval)delay; 83 | 84 | /** 85 | * 86 | * Access the singleton Crashlytics instance. 87 | * 88 | **/ 89 | + (Crashlytics *)sharedInstance; 90 | 91 | /** 92 | * 93 | * The easiest way to cause a crash - great for testing! 94 | * 95 | **/ 96 | - (void)crash; 97 | 98 | /** 99 | * 100 | * Many of our customers have requested the ability to tie crashes to specific end-users of their 101 | * application in order to facilitate responses to support requests or permit the ability to reach 102 | * out for more information. We allow you to specify up to three separate values for display within 103 | * the Crashlytics UI - but please be mindful of your end-user's privacy. 104 | * 105 | * We recommend specifying a user identifier - an arbitrary string that ties an end-user to a record 106 | * in your system. This could be a database id, hash, or other value that is meaningless to a 107 | * third-party observer but can be indexed and queried by you. 108 | * 109 | * Optionally, you may also specify the end-user's name or username, as well as email address if you 110 | * do not have a system that works well with obscured identifiers. 111 | * 112 | * Pursuant to our EULA, this data is transferred securely throughout our system and we will not 113 | * disseminate end-user data unless required to by law. That said, if you choose to provide end-user 114 | * contact information, we strongly recommend that you disclose this in your application's privacy 115 | * policy. Data privacy is of our utmost concern. 116 | * 117 | **/ 118 | - (void)setUserIdentifier:(NSString *)identifier; 119 | - (void)setUserName:(NSString *)name; 120 | - (void)setUserEmail:(NSString *)email; 121 | 122 | + (void)setUserIdentifier:(NSString *)identifier; 123 | + (void)setUserName:(NSString *)name; 124 | + (void)setUserEmail:(NSString *)email; 125 | 126 | /** 127 | * 128 | * Set a value for a key to be associated with your crash data. 129 | * 130 | **/ 131 | - (void)setObjectValue:(id)value forKey:(NSString *)key; 132 | - (void)setIntValue:(int)value forKey:(NSString *)key; 133 | - (void)setBoolValue:(BOOL)value forKey:(NSString *)key; 134 | - (void)setFloatValue:(float)value forKey:(NSString *)key; 135 | 136 | + (void)setObjectValue:(id)value forKey:(NSString *)key; 137 | + (void)setIntValue:(int)value forKey:(NSString *)key; 138 | + (void)setBoolValue:(BOOL)value forKey:(NSString *)key; 139 | + (void)setFloatValue:(float)value forKey:(NSString *)key; 140 | 141 | @end 142 | 143 | /** 144 | * The CLSCrashReport protocol exposes methods that you can call on crash report objects passed 145 | * to delegate methods. If you want these values or the entire object to stay in memory retain 146 | * them or copy them. 147 | **/ 148 | @protocol CLSCrashReport 149 | @required 150 | 151 | /** 152 | * Returns the session identifier for the crash report. 153 | **/ 154 | @property (nonatomic, readonly) NSString *identifier; 155 | 156 | /** 157 | * Returns the custom key value data for the crash report. 158 | **/ 159 | @property (nonatomic, readonly) NSDictionary *customKeys; 160 | 161 | /** 162 | * Returns the CFBundleVersion of the application that crashed. 163 | **/ 164 | @property (nonatomic, readonly) NSString *bundleVersion; 165 | 166 | /** 167 | * Returns the CFBundleShortVersionString of the application that crashed. 168 | **/ 169 | @property (nonatomic, readonly) NSString *bundleShortVersionString; 170 | 171 | /** 172 | * Returns the date that the application crashed at. 173 | **/ 174 | @property (nonatomic, readonly) NSDate *crashedOnDate; 175 | 176 | /** 177 | * Returns the os version that the application crashed on. 178 | **/ 179 | @property (nonatomic, readonly) NSString *OSVersion; 180 | 181 | /** 182 | * Returns the os build version that the application crashed on. 183 | **/ 184 | @property (nonatomic, readonly) NSString *OSBuildVersion; 185 | 186 | @end 187 | 188 | /** 189 | * 190 | * The CrashlyticsDelegate protocol provides a mechanism for your application to take 191 | * action on events that occur in the Crashlytics crash reporting system. You can make 192 | * use of these calls by assigning an object to the Crashlytics' delegate property directly, 193 | * or through the convenience startWithAPIKey:delegate:... methods. 194 | * 195 | **/ 196 | @protocol CrashlyticsDelegate 197 | @optional 198 | 199 | /** 200 | * 201 | * Called once a Crashlytics instance has determined that the last execution of the 202 | * application ended in a crash. This is called some time after the crash reporting 203 | * process has begun. If you have specified a delay in one of the 204 | * startWithAPIKey:... calls, this will take at least that long to be invoked. 205 | * 206 | **/ 207 | - (void)crashlyticsDidDetectCrashDuringPreviousExecution:(Crashlytics *)crashlytics; 208 | 209 | /** 210 | * 211 | * Just like crashlyticsDidDetectCrashDuringPreviousExecution this delegate method is 212 | * called once a Crashlytics instance has determined that the last execution of the 213 | * application ended in a crash. A CLSCrashReport is passed back that contains data about 214 | * the last crash report that was generated. See the CLSCrashReport protocol for method details. 215 | * This method is called after crashlyticsDidDetectCrashDuringPreviousExecution. 216 | * 217 | **/ 218 | - (void)crashlytics:(Crashlytics *)crashlytics didDetectCrashDuringPreviousExecution:(id )crash; 219 | 220 | @end 221 | -------------------------------------------------------------------------------- /iOS/DesignPatternsSample/Crashlytics.framework/Versions/A/Headers/Crashlytics.h: -------------------------------------------------------------------------------- 1 | // 2 | // Crashlytics.h 3 | // Crashlytics 4 | // 5 | // Copyright 2013 Crashlytics, Inc. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | /** 11 | * 12 | * The CLS_LOG macro provides as easy way to gather more information in your log messages that are 13 | * sent with your crash data. CLS_LOG prepends your custom log message with the function name and 14 | * line number where the macro was used. If your app was built with the DEBUG preprocessor macro 15 | * defined CLS_LOG uses the CLSNSLog function which forwards your log message to NSLog and CLSLog. 16 | * If the DEBUG preprocessor macro is not defined CLS_LOG uses CLSLog only. 17 | * 18 | * Example output: 19 | * -[AppDelegate login:] line 134 $ login start 20 | * 21 | * If you would like to change this macro, create a new header file, unset our define and then define 22 | * your own version. Make sure this new header file is imported after the Crashlytics header file. 23 | * 24 | * #undef CLS_LOG 25 | * #define CLS_LOG(__FORMAT__, ...) CLSNSLog... 26 | * 27 | **/ 28 | #ifdef DEBUG 29 | #define CLS_LOG(__FORMAT__, ...) CLSNSLog((@"%s line %d $ " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__) 30 | #else 31 | #define CLS_LOG(__FORMAT__, ...) CLSLog((@"%s line %d $ " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__) 32 | #endif 33 | 34 | /** 35 | * 36 | * Add logging that will be sent with your crash data. This logging will not show up in the system.log 37 | * and will only be visible in your Crashlytics dashboard. 38 | * 39 | **/ 40 | OBJC_EXTERN void CLSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2); 41 | OBJC_EXTERN void CLSLogv(NSString *format, va_list args) NS_FORMAT_FUNCTION(1,0); 42 | 43 | /** 44 | * 45 | * Add logging that will be sent with your crash data. This logging will show up in the system.log 46 | * and your Crashlytics dashboard. It is not recommended for Release builds. 47 | * 48 | **/ 49 | OBJC_EXTERN void CLSNSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2); 50 | OBJC_EXTERN void CLSNSLogv(NSString *format, va_list args) NS_FORMAT_FUNCTION(1,0); 51 | 52 | 53 | @protocol CrashlyticsDelegate; 54 | 55 | @interface Crashlytics : NSObject 56 | 57 | @property (nonatomic, readonly, copy) NSString *apiKey; 58 | @property (nonatomic, readonly, copy) NSString *version; 59 | @property (nonatomic, assign) BOOL debugMode; 60 | 61 | @property (nonatomic, assign) NSObject *delegate; 62 | 63 | /** 64 | * 65 | * The recommended way to install Crashlytics into your application is to place a call 66 | * to +startWithAPIKey: in your -application:didFinishLaunchingWithOptions: method. 67 | * 68 | * This delay defaults to 1 second in order to generally give the application time to 69 | * fully finish launching. 70 | * 71 | **/ 72 | + (Crashlytics *)startWithAPIKey:(NSString *)apiKey; 73 | + (Crashlytics *)startWithAPIKey:(NSString *)apiKey afterDelay:(NSTimeInterval)delay; 74 | 75 | /** 76 | * 77 | * If you need the functionality provided by the CrashlyticsDelegate protocol, you can use 78 | * these convenience methods to activate the framework and set the delegate in one call. 79 | * 80 | **/ 81 | + (Crashlytics *)startWithAPIKey:(NSString *)apiKey delegate:(NSObject *)delegate; 82 | + (Crashlytics *)startWithAPIKey:(NSString *)apiKey delegate:(NSObject *)delegate afterDelay:(NSTimeInterval)delay; 83 | 84 | /** 85 | * 86 | * Access the singleton Crashlytics instance. 87 | * 88 | **/ 89 | + (Crashlytics *)sharedInstance; 90 | 91 | /** 92 | * 93 | * The easiest way to cause a crash - great for testing! 94 | * 95 | **/ 96 | - (void)crash; 97 | 98 | /** 99 | * 100 | * Many of our customers have requested the ability to tie crashes to specific end-users of their 101 | * application in order to facilitate responses to support requests or permit the ability to reach 102 | * out for more information. We allow you to specify up to three separate values for display within 103 | * the Crashlytics UI - but please be mindful of your end-user's privacy. 104 | * 105 | * We recommend specifying a user identifier - an arbitrary string that ties an end-user to a record 106 | * in your system. This could be a database id, hash, or other value that is meaningless to a 107 | * third-party observer but can be indexed and queried by you. 108 | * 109 | * Optionally, you may also specify the end-user's name or username, as well as email address if you 110 | * do not have a system that works well with obscured identifiers. 111 | * 112 | * Pursuant to our EULA, this data is transferred securely throughout our system and we will not 113 | * disseminate end-user data unless required to by law. That said, if you choose to provide end-user 114 | * contact information, we strongly recommend that you disclose this in your application's privacy 115 | * policy. Data privacy is of our utmost concern. 116 | * 117 | **/ 118 | - (void)setUserIdentifier:(NSString *)identifier; 119 | - (void)setUserName:(NSString *)name; 120 | - (void)setUserEmail:(NSString *)email; 121 | 122 | + (void)setUserIdentifier:(NSString *)identifier; 123 | + (void)setUserName:(NSString *)name; 124 | + (void)setUserEmail:(NSString *)email; 125 | 126 | /** 127 | * 128 | * Set a value for a key to be associated with your crash data. 129 | * 130 | **/ 131 | - (void)setObjectValue:(id)value forKey:(NSString *)key; 132 | - (void)setIntValue:(int)value forKey:(NSString *)key; 133 | - (void)setBoolValue:(BOOL)value forKey:(NSString *)key; 134 | - (void)setFloatValue:(float)value forKey:(NSString *)key; 135 | 136 | + (void)setObjectValue:(id)value forKey:(NSString *)key; 137 | + (void)setIntValue:(int)value forKey:(NSString *)key; 138 | + (void)setBoolValue:(BOOL)value forKey:(NSString *)key; 139 | + (void)setFloatValue:(float)value forKey:(NSString *)key; 140 | 141 | @end 142 | 143 | /** 144 | * The CLSCrashReport protocol exposes methods that you can call on crash report objects passed 145 | * to delegate methods. If you want these values or the entire object to stay in memory retain 146 | * them or copy them. 147 | **/ 148 | @protocol CLSCrashReport 149 | @required 150 | 151 | /** 152 | * Returns the session identifier for the crash report. 153 | **/ 154 | @property (nonatomic, readonly) NSString *identifier; 155 | 156 | /** 157 | * Returns the custom key value data for the crash report. 158 | **/ 159 | @property (nonatomic, readonly) NSDictionary *customKeys; 160 | 161 | /** 162 | * Returns the CFBundleVersion of the application that crashed. 163 | **/ 164 | @property (nonatomic, readonly) NSString *bundleVersion; 165 | 166 | /** 167 | * Returns the CFBundleShortVersionString of the application that crashed. 168 | **/ 169 | @property (nonatomic, readonly) NSString *bundleShortVersionString; 170 | 171 | /** 172 | * Returns the date that the application crashed at. 173 | **/ 174 | @property (nonatomic, readonly) NSDate *crashedOnDate; 175 | 176 | /** 177 | * Returns the os version that the application crashed on. 178 | **/ 179 | @property (nonatomic, readonly) NSString *OSVersion; 180 | 181 | /** 182 | * Returns the os build version that the application crashed on. 183 | **/ 184 | @property (nonatomic, readonly) NSString *OSBuildVersion; 185 | 186 | @end 187 | 188 | /** 189 | * 190 | * The CrashlyticsDelegate protocol provides a mechanism for your application to take 191 | * action on events that occur in the Crashlytics crash reporting system. You can make 192 | * use of these calls by assigning an object to the Crashlytics' delegate property directly, 193 | * or through the convenience startWithAPIKey:delegate:... methods. 194 | * 195 | **/ 196 | @protocol CrashlyticsDelegate 197 | @optional 198 | 199 | /** 200 | * 201 | * Called once a Crashlytics instance has determined that the last execution of the 202 | * application ended in a crash. This is called some time after the crash reporting 203 | * process has begun. If you have specified a delay in one of the 204 | * startWithAPIKey:... calls, this will take at least that long to be invoked. 205 | * 206 | **/ 207 | - (void)crashlyticsDidDetectCrashDuringPreviousExecution:(Crashlytics *)crashlytics; 208 | 209 | /** 210 | * 211 | * Just like crashlyticsDidDetectCrashDuringPreviousExecution this delegate method is 212 | * called once a Crashlytics instance has determined that the last execution of the 213 | * application ended in a crash. A CLSCrashReport is passed back that contains data about 214 | * the last crash report that was generated. See the CLSCrashReport protocol for method details. 215 | * This method is called after crashlyticsDidDetectCrashDuringPreviousExecution. 216 | * 217 | **/ 218 | - (void)crashlytics:(Crashlytics *)crashlytics didDetectCrashDuringPreviousExecution:(id )crash; 219 | 220 | @end 221 | -------------------------------------------------------------------------------- /iOS/DesignPatternsSample/Crashlytics.framework/Versions/Current/Headers/Crashlytics.h: -------------------------------------------------------------------------------- 1 | // 2 | // Crashlytics.h 3 | // Crashlytics 4 | // 5 | // Copyright 2013 Crashlytics, Inc. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | /** 11 | * 12 | * The CLS_LOG macro provides as easy way to gather more information in your log messages that are 13 | * sent with your crash data. CLS_LOG prepends your custom log message with the function name and 14 | * line number where the macro was used. If your app was built with the DEBUG preprocessor macro 15 | * defined CLS_LOG uses the CLSNSLog function which forwards your log message to NSLog and CLSLog. 16 | * If the DEBUG preprocessor macro is not defined CLS_LOG uses CLSLog only. 17 | * 18 | * Example output: 19 | * -[AppDelegate login:] line 134 $ login start 20 | * 21 | * If you would like to change this macro, create a new header file, unset our define and then define 22 | * your own version. Make sure this new header file is imported after the Crashlytics header file. 23 | * 24 | * #undef CLS_LOG 25 | * #define CLS_LOG(__FORMAT__, ...) CLSNSLog... 26 | * 27 | **/ 28 | #ifdef DEBUG 29 | #define CLS_LOG(__FORMAT__, ...) CLSNSLog((@"%s line %d $ " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__) 30 | #else 31 | #define CLS_LOG(__FORMAT__, ...) CLSLog((@"%s line %d $ " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__) 32 | #endif 33 | 34 | /** 35 | * 36 | * Add logging that will be sent with your crash data. This logging will not show up in the system.log 37 | * and will only be visible in your Crashlytics dashboard. 38 | * 39 | **/ 40 | OBJC_EXTERN void CLSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2); 41 | OBJC_EXTERN void CLSLogv(NSString *format, va_list args) NS_FORMAT_FUNCTION(1,0); 42 | 43 | /** 44 | * 45 | * Add logging that will be sent with your crash data. This logging will show up in the system.log 46 | * and your Crashlytics dashboard. It is not recommended for Release builds. 47 | * 48 | **/ 49 | OBJC_EXTERN void CLSNSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2); 50 | OBJC_EXTERN void CLSNSLogv(NSString *format, va_list args) NS_FORMAT_FUNCTION(1,0); 51 | 52 | 53 | @protocol CrashlyticsDelegate; 54 | 55 | @interface Crashlytics : NSObject 56 | 57 | @property (nonatomic, readonly, copy) NSString *apiKey; 58 | @property (nonatomic, readonly, copy) NSString *version; 59 | @property (nonatomic, assign) BOOL debugMode; 60 | 61 | @property (nonatomic, assign) NSObject *delegate; 62 | 63 | /** 64 | * 65 | * The recommended way to install Crashlytics into your application is to place a call 66 | * to +startWithAPIKey: in your -application:didFinishLaunchingWithOptions: method. 67 | * 68 | * This delay defaults to 1 second in order to generally give the application time to 69 | * fully finish launching. 70 | * 71 | **/ 72 | + (Crashlytics *)startWithAPIKey:(NSString *)apiKey; 73 | + (Crashlytics *)startWithAPIKey:(NSString *)apiKey afterDelay:(NSTimeInterval)delay; 74 | 75 | /** 76 | * 77 | * If you need the functionality provided by the CrashlyticsDelegate protocol, you can use 78 | * these convenience methods to activate the framework and set the delegate in one call. 79 | * 80 | **/ 81 | + (Crashlytics *)startWithAPIKey:(NSString *)apiKey delegate:(NSObject *)delegate; 82 | + (Crashlytics *)startWithAPIKey:(NSString *)apiKey delegate:(NSObject *)delegate afterDelay:(NSTimeInterval)delay; 83 | 84 | /** 85 | * 86 | * Access the singleton Crashlytics instance. 87 | * 88 | **/ 89 | + (Crashlytics *)sharedInstance; 90 | 91 | /** 92 | * 93 | * The easiest way to cause a crash - great for testing! 94 | * 95 | **/ 96 | - (void)crash; 97 | 98 | /** 99 | * 100 | * Many of our customers have requested the ability to tie crashes to specific end-users of their 101 | * application in order to facilitate responses to support requests or permit the ability to reach 102 | * out for more information. We allow you to specify up to three separate values for display within 103 | * the Crashlytics UI - but please be mindful of your end-user's privacy. 104 | * 105 | * We recommend specifying a user identifier - an arbitrary string that ties an end-user to a record 106 | * in your system. This could be a database id, hash, or other value that is meaningless to a 107 | * third-party observer but can be indexed and queried by you. 108 | * 109 | * Optionally, you may also specify the end-user's name or username, as well as email address if you 110 | * do not have a system that works well with obscured identifiers. 111 | * 112 | * Pursuant to our EULA, this data is transferred securely throughout our system and we will not 113 | * disseminate end-user data unless required to by law. That said, if you choose to provide end-user 114 | * contact information, we strongly recommend that you disclose this in your application's privacy 115 | * policy. Data privacy is of our utmost concern. 116 | * 117 | **/ 118 | - (void)setUserIdentifier:(NSString *)identifier; 119 | - (void)setUserName:(NSString *)name; 120 | - (void)setUserEmail:(NSString *)email; 121 | 122 | + (void)setUserIdentifier:(NSString *)identifier; 123 | + (void)setUserName:(NSString *)name; 124 | + (void)setUserEmail:(NSString *)email; 125 | 126 | /** 127 | * 128 | * Set a value for a key to be associated with your crash data. 129 | * 130 | **/ 131 | - (void)setObjectValue:(id)value forKey:(NSString *)key; 132 | - (void)setIntValue:(int)value forKey:(NSString *)key; 133 | - (void)setBoolValue:(BOOL)value forKey:(NSString *)key; 134 | - (void)setFloatValue:(float)value forKey:(NSString *)key; 135 | 136 | + (void)setObjectValue:(id)value forKey:(NSString *)key; 137 | + (void)setIntValue:(int)value forKey:(NSString *)key; 138 | + (void)setBoolValue:(BOOL)value forKey:(NSString *)key; 139 | + (void)setFloatValue:(float)value forKey:(NSString *)key; 140 | 141 | @end 142 | 143 | /** 144 | * The CLSCrashReport protocol exposes methods that you can call on crash report objects passed 145 | * to delegate methods. If you want these values or the entire object to stay in memory retain 146 | * them or copy them. 147 | **/ 148 | @protocol CLSCrashReport 149 | @required 150 | 151 | /** 152 | * Returns the session identifier for the crash report. 153 | **/ 154 | @property (nonatomic, readonly) NSString *identifier; 155 | 156 | /** 157 | * Returns the custom key value data for the crash report. 158 | **/ 159 | @property (nonatomic, readonly) NSDictionary *customKeys; 160 | 161 | /** 162 | * Returns the CFBundleVersion of the application that crashed. 163 | **/ 164 | @property (nonatomic, readonly) NSString *bundleVersion; 165 | 166 | /** 167 | * Returns the CFBundleShortVersionString of the application that crashed. 168 | **/ 169 | @property (nonatomic, readonly) NSString *bundleShortVersionString; 170 | 171 | /** 172 | * Returns the date that the application crashed at. 173 | **/ 174 | @property (nonatomic, readonly) NSDate *crashedOnDate; 175 | 176 | /** 177 | * Returns the os version that the application crashed on. 178 | **/ 179 | @property (nonatomic, readonly) NSString *OSVersion; 180 | 181 | /** 182 | * Returns the os build version that the application crashed on. 183 | **/ 184 | @property (nonatomic, readonly) NSString *OSBuildVersion; 185 | 186 | @end 187 | 188 | /** 189 | * 190 | * The CrashlyticsDelegate protocol provides a mechanism for your application to take 191 | * action on events that occur in the Crashlytics crash reporting system. You can make 192 | * use of these calls by assigning an object to the Crashlytics' delegate property directly, 193 | * or through the convenience startWithAPIKey:delegate:... methods. 194 | * 195 | **/ 196 | @protocol CrashlyticsDelegate 197 | @optional 198 | 199 | /** 200 | * 201 | * Called once a Crashlytics instance has determined that the last execution of the 202 | * application ended in a crash. This is called some time after the crash reporting 203 | * process has begun. If you have specified a delay in one of the 204 | * startWithAPIKey:... calls, this will take at least that long to be invoked. 205 | * 206 | **/ 207 | - (void)crashlyticsDidDetectCrashDuringPreviousExecution:(Crashlytics *)crashlytics; 208 | 209 | /** 210 | * 211 | * Just like crashlyticsDidDetectCrashDuringPreviousExecution this delegate method is 212 | * called once a Crashlytics instance has determined that the last execution of the 213 | * application ended in a crash. A CLSCrashReport is passed back that contains data about 214 | * the last crash report that was generated. See the CLSCrashReport protocol for method details. 215 | * This method is called after crashlyticsDidDetectCrashDuringPreviousExecution. 216 | * 217 | **/ 218 | - (void)crashlytics:(Crashlytics *)crashlytics didDetectCrashDuringPreviousExecution:(id )crash; 219 | 220 | @end 221 | --------------------------------------------------------------------------------